diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 434684e137..e3afc8e004 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -850,6 +850,10 @@ msgstr "" msgid "Error in regex" msgstr "" +#: shared-bindings/socketpool/Socket.c +msgid "Error: Failure to bind" +msgstr "" + #: py/enum.c shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c #: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c @@ -1240,10 +1244,18 @@ msgstr "" msgid "Invalid size" msgstr "" +#: ports/esp32s2/common-hal/socketpool/Socket.c +msgid "Invalid socket for TLS" +msgstr "" + #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Invalid state" msgstr "" +#: ports/esp32s2/common-hal/socketpool/Socket.c +msgid "Invalid use of TLS Socket" +msgstr "" + #: shared-bindings/audiomixer/Mixer.c msgid "Invalid voice" msgstr "" @@ -1260,6 +1272,10 @@ msgstr "" msgid "Invalid word/bit length" msgstr "" +#: ports/esp32s2/common-hal/socketpool/Socket.c +msgid "Issue setting SO_REUSEADDR" +msgstr "" + #: shared-bindings/aesio/aes.c msgid "Key must be 16, 24, or 32 bytes long" msgstr "" @@ -1542,7 +1558,7 @@ msgstr "" msgid "Out of memory" msgstr "" -#: ports/esp32s2/common-hal/socketpool/SocketPool.c +#: ports/esp32s2/common-hal/socketpool/Socket.c msgid "Out of sockets" msgstr "" diff --git a/ports/esp32s2/common-hal/socketpool/Socket.c b/ports/esp32s2/common-hal/socketpool/Socket.c index 5e943f8fd0..69ef41c6ec 100644 --- a/ports/esp32s2/common-hal/socketpool/Socket.c +++ b/ports/esp32s2/common-hal/socketpool/Socket.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * 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 @@ -37,25 +38,162 @@ #include "components/lwip/lwip/src/include/lwip/sys.h" #include "components/lwip/lwip/src/include/lwip/netdb.h" +STATIC socketpool_socket_obj_t * open_socket_handles[CONFIG_LWIP_MAX_SOCKETS]; // 4 on the wrover/wroom + +void socket_reset(void) { + for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) { + if (open_socket_handles[i]) { + if (open_socket_handles[i]->num > 0) { + common_hal_socketpool_socket_close(open_socket_handles[i]); + open_socket_handles[i] = NULL; + } else { + // accidentally got a TCP socket in here, or something. + open_socket_handles[i] = NULL; + } + } + } +} + +bool register_open_socket(socketpool_socket_obj_t* self) { + for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) { + if (open_socket_handles[i] == NULL) { + open_socket_handles[i] = self; + return true; + } + } + return false; +} + +STATIC void _lazy_init_LWIP(socketpool_socket_obj_t* self) { + if (self->num != -1) { + return; //safe to call on existing socket + } + if (self->tls != NULL) { + mp_raise_RuntimeError(translate("Invalid use of TLS Socket")); + } + int socknum = -1; + socknum = lwip_socket(self->family, self->type, self->ipproto); + if (socknum < 0 || !register_open_socket(self)) { + mp_raise_RuntimeError(translate("Out of sockets")); + } + self->num = socknum; + lwip_fcntl(socknum, F_SETFL, O_NONBLOCK); +} + +STATIC void _lazy_init_TLS(socketpool_socket_obj_t* self) { + if (self->type != SOCK_STREAM || self->num != -1) { + mp_raise_RuntimeError(translate("Invalid socket for TLS")); + } + esp_tls_t* tls_handle = esp_tls_init(); + if (tls_handle == NULL) { + mp_raise_espidf_MemoryError(); + } + self->tls = tls_handle; +} + void common_hal_socketpool_socket_settimeout(socketpool_socket_obj_t* self, mp_uint_t timeout_ms) { self->timeout_ms = timeout_ms; } -bool common_hal_socketpool_socket_connect(socketpool_socket_obj_t* self, const char* host, mp_uint_t hostlen, mp_int_t port) { +bool common_hal_socketpool_socket_bind(socketpool_socket_obj_t* self, + const char* host, size_t hostlen, uint8_t port) { + _lazy_init_LWIP(self); + + struct sockaddr_in bind_addr; + bind_addr.sin_addr.s_addr = inet_addr(host); + bind_addr.sin_family = AF_INET; + bind_addr.sin_port = htons(port); + + int opt = 1; + int err = lwip_setsockopt(self->num, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + if (err != 0) { + mp_raise_RuntimeError(translate("Issue setting SO_REUSEADDR")); + } + int result = lwip_bind(self->num, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) == 0; + return result; +} + +bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t* self, int backlog) { + return lwip_listen(self->num, backlog) == 0; +} + +socketpool_socket_obj_t* common_hal_socketpool_socket_accept(socketpool_socket_obj_t* self, + uint8_t* ip, uint *port) { + struct sockaddr_in accept_addr; + socklen_t socklen = sizeof(accept_addr); + int newsoc = -1; + bool timed_out = false; + uint64_t start_ticks = supervisor_ticks_ms64(); + + if (self->timeout_ms != (uint)-1) { + mp_printf(&mp_plat_print, "will timeout"); + } else { + mp_printf(&mp_plat_print, "won't timeout"); + } + + // Allow timeouts and interrupts + while (newsoc == -1 && + !timed_out && + !mp_hal_is_interrupted()) { + if (self->timeout_ms != (uint)-1) { + timed_out = supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; + } + RUN_BACKGROUND_TASKS; + newsoc = lwip_accept(self->num, (struct sockaddr *)&accept_addr, &socklen); + // In non-blocking mode, fail instead of looping + if (newsoc == -1 && self->timeout_ms == 0) { + mp_raise_OSError(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 { + mp_raise_OSError(ETIMEDOUT); + } + + if (newsoc > 0) { + // Create the socket + socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t); + sock->base.type = &socketpool_socket_type; + sock->num = newsoc; + sock->tls = NULL; + sock->ssl_context = NULL; + sock->pool = self->pool; + + if (!register_open_socket(sock)) { + mp_raise_OSError(MP_EBADF); + } + + lwip_fcntl(newsoc, F_SETFL, O_NONBLOCK); + return sock; + } else { + mp_raise_OSError(MP_EBADF); + return NULL; + } +} + +bool common_hal_socketpool_socket_connect(socketpool_socket_obj_t* self, + const char* host, mp_uint_t hostlen, mp_int_t port) { // For simplicity we use esp_tls for all TCP connections. If it's not SSL, ssl_context will be // NULL and should still work. This makes regular TCP connections more memory expensive but TLS // should become more and more common. Therefore, we optimize for the TLS case. + // Todo: move to SSL Wrapper and add lwip_connect() + _lazy_init_TLS(self); + esp_tls_cfg_t* tls_config = NULL; if (self->ssl_context != NULL) { tls_config = &self->ssl_context->ssl_config; } - int result = esp_tls_conn_new_sync(host, hostlen, port, tls_config, self->tcp); + int result = esp_tls_conn_new_sync(host, hostlen, port, tls_config, self->tls); self->connected = result >= 0; if (result < 0) { int esp_tls_code; int flags; - esp_err_t err = esp_tls_get_and_clear_last_error(self->tcp->error_handle, &esp_tls_code, &flags); + esp_err_t err = esp_tls_get_and_clear_last_error(self->tls->error_handle, &esp_tls_code, &flags); if (err == ESP_ERR_MBEDTLS_SSL_SETUP_FAILED) { mp_raise_espidf_MemoryError(); @@ -70,7 +208,7 @@ bool common_hal_socketpool_socket_connect(socketpool_socket_obj_t* self, const c // shouldn't hit this timeout because we try to only read available data. However, there is // always a chance that we try to read something that is used internally. int fd; - esp_tls_get_conn_sockfd(self->tcp, &fd); + esp_tls_get_conn_sockfd(self->tls, &fd); struct timeval tv; tv.tv_sec = 2 * 60; // Two minutes tv.tv_usec = 0; @@ -86,7 +224,15 @@ bool common_hal_socketpool_socket_get_connected(socketpool_socket_obj_t* self) { } mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t* self, const uint8_t* buf, mp_uint_t len) { - size_t sent = esp_tls_conn_write(self->tcp, buf, len); + int sent = -1; + if (self->num != -1) { + // LWIP Socket + // TODO: deal with potential failure/add timeout? + sent = lwip_send(self->num, buf, len, 0); + } else if (self->tls != NULL) { + // TLS Socket + sent = esp_tls_conn_write(self->tls, buf, len); + } if (sent < 0) { mp_raise_OSError(MP_ENOTCONN); @@ -95,45 +241,73 @@ mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t* self, const } mp_uint_t common_hal_socketpool_socket_recv_into(socketpool_socket_obj_t* self, const uint8_t* buf, mp_uint_t len) { - size_t received = 0; - int status = 0; - uint64_t start_ticks = supervisor_ticks_ms64(); - int sockfd; - esp_err_t err = esp_tls_get_conn_sockfd(self->tcp, &sockfd); - if (err != ESP_OK) { + int received = 0; + bool timed_out = false; + + if (self->num != -1) { + // LWIP Socket + uint64_t start_ticks = supervisor_ticks_ms64(); + received = -1; + while (received == -1 && + !timed_out && + !mp_hal_is_interrupted()) { + if (self->timeout_ms != (uint)-1) { + timed_out = supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; + } + RUN_BACKGROUND_TASKS; + received = lwip_recv(self->num, (void*) buf, len - 1, 0); + + // In non-blocking mode, fail instead of looping + if (received == -1 && self->timeout_ms == 0) { + mp_raise_OSError(MP_EAGAIN); + } + } + } else if (self->tls != NULL) { + // TLS Socket + int status = 0; + uint64_t start_ticks = supervisor_ticks_ms64(); + int sockfd; + esp_err_t err = esp_tls_get_conn_sockfd(self->tls, &sockfd); + if (err != ESP_OK) { + mp_raise_OSError(MP_EBADF); + } + while (received == 0 && + status >= 0 && + !timed_out && + !mp_hal_is_interrupted()) { + if (self->timeout_ms != (uint)-1) { + timed_out = self->timeout_ms == 0 || supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; + } + RUN_BACKGROUND_TASKS; + size_t available = esp_tls_get_bytes_avail(self->tls); + if (available == 0) { + // This reads the raw socket buffer and is used for non-TLS connections + // and between encrypted TLS blocks. + status = lwip_ioctl(sockfd, FIONREAD, &available); + } + size_t remaining = len - received; + if (available > remaining) { + available = remaining; + } + if (available > 0) { + status = esp_tls_conn_read(self->tls, (void*) buf + received, available); + if (status == 0) { + // Reading zero when something is available indicates a closed + // connection. (The available bytes could have been TLS internal.) + break; + } + if (status > 0) { + received += status; + } + } + } + } else { + // Socket does not have a valid descriptor of either type mp_raise_OSError(MP_EBADF); } - while (received == 0 && - status >= 0 && - (self->timeout_ms == 0 || supervisor_ticks_ms64() - start_ticks <= self->timeout_ms) && - !mp_hal_is_interrupted()) { - RUN_BACKGROUND_TASKS; - size_t available = esp_tls_get_bytes_avail(self->tcp); - if (available == 0) { - // This reads the raw socket buffer and is used for non-TLS connections - // and between encrypted TLS blocks. - status = lwip_ioctl(sockfd, FIONREAD, &available); - } - size_t remaining = len - received; - if (available > remaining) { - available = remaining; - } - if (available > 0) { - status = esp_tls_conn_read(self->tcp, (void*) buf + received, available); - if (status == 0) { - // Reading zero when something is available indicates a closed - // connection. (The available bytes could have been TLS internal.) - break; - } - if (status > 0) { - received += status; - } - } - } - if (received == 0) { - // socket closed - common_hal_socketpool_socket_close(self); + if (timed_out) { + mp_raise_OSError(ETIMEDOUT); } return received; } @@ -141,6 +315,8 @@ mp_uint_t common_hal_socketpool_socket_recv_into(socketpool_socket_obj_t* self, mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t* self, const char* host, size_t hostlen, uint8_t port, const uint8_t* buf, mp_uint_t len) { + _lazy_init_LWIP(self); + // Get the IP address string const struct addrinfo hints = { .ai_family = AF_INET, @@ -151,17 +327,15 @@ mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t* self, if (error != 0 || result == NULL) { return 0; } - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - struct in_addr *addr = &((struct sockaddr_in *)result->ai_addr)->sin_addr; - #pragma GCC diagnostic pop - char ip_str[IP4ADDR_STRLEN_MAX]; - inet_ntoa_r(*addr, ip_str, IP4ADDR_STRLEN_MAX); - freeaddrinfo(result); // Set parameters struct sockaddr_in dest_addr; - dest_addr.sin_addr.s_addr = inet_addr((const char *)ip_str); + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + dest_addr.sin_addr.s_addr = ((struct sockaddr_in *)result->ai_addr)->sin_addr.s_addr; + #pragma GCC diagnostic pop + freeaddrinfo(result); + dest_addr.sin_family = AF_INET; dest_addr.sin_port = htons(port); @@ -176,26 +350,50 @@ mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t* self, mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t* self, uint8_t* buf, mp_uint_t len, uint8_t* ip, uint *port) { + _lazy_init_LWIP(self); + struct sockaddr_in source_addr; socklen_t socklen = sizeof(source_addr); - int bytes_received = lwip_recvfrom(self->num, buf, len, 0, (struct sockaddr *)&source_addr, &socklen); - memcpy((void *)ip, (void*)&source_addr.sin_addr.s_addr, sizeof source_addr.sin_addr.s_addr); - *port = source_addr.sin_port; + // LWIP Socket + uint64_t start_ticks = supervisor_ticks_ms64(); + int received = -1; + bool timed_out = false; + while (received == -1 && + !timed_out && + !mp_hal_is_interrupted()) { + if (self->timeout_ms != (uint)-1) { + timed_out = supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; + } + RUN_BACKGROUND_TASKS; + received = lwip_recvfrom(self->num, buf, len, 0, (struct sockaddr *)&source_addr, &socklen); - if (bytes_received < 0) { + // In non-blocking mode, fail instead of looping + if (received == -1 && self->timeout_ms == 0) { + mp_raise_OSError(MP_EAGAIN); + } + } + + if (!timed_out) { + memcpy((void *)ip, (void*)&source_addr.sin_addr.s_addr, sizeof(source_addr.sin_addr.s_addr)); + *port = source_addr.sin_port; + } else { + mp_raise_OSError(ETIMEDOUT); + } + + if (received < 0) { mp_raise_BrokenPipeError(); return 0; } - return bytes_received; + return received; } void common_hal_socketpool_socket_close(socketpool_socket_obj_t* self) { self->connected = false; - if (self->tcp != NULL) { - esp_tls_conn_destroy(self->tcp); - self->tcp = NULL; + if (self->tls != NULL) { + esp_tls_conn_destroy(self->tls); + self->tls = NULL; } if (self->num >= 0) { lwip_shutdown(self->num, 0); @@ -205,7 +403,7 @@ void common_hal_socketpool_socket_close(socketpool_socket_obj_t* self) { } bool common_hal_socketpool_socket_get_closed(socketpool_socket_obj_t* self) { - return self->tcp == NULL && self->num < 0; + return self->tls == NULL && self->num < 0; } diff --git a/ports/esp32s2/common-hal/socketpool/Socket.h b/ports/esp32s2/common-hal/socketpool/Socket.h index 62b5ded58e..4e6cfa5ef6 100644 --- a/ports/esp32s2/common-hal/socketpool/Socket.h +++ b/ports/esp32s2/common-hal/socketpool/Socket.h @@ -37,11 +37,17 @@ typedef struct { mp_obj_base_t base; int num; + int type; + int family; + int ipproto; bool connected; - esp_tls_t* tcp; + esp_tls_t* tls; ssl_sslcontext_obj_t* ssl_context; socketpool_socketpool_obj_t* pool; mp_uint_t timeout_ms; } socketpool_socket_obj_t; +void socket_reset(void); +bool register_open_socket(socketpool_socket_obj_t* self); + #endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_SOCKETPOOL_SOCKET_H diff --git a/ports/esp32s2/common-hal/socketpool/SocketPool.c b/ports/esp32s2/common-hal/socketpool/SocketPool.c index 3bec5f337f..5821728ce5 100644 --- a/ports/esp32s2/common-hal/socketpool/SocketPool.c +++ b/ports/esp32s2/common-hal/socketpool/SocketPool.c @@ -65,25 +65,20 @@ socketpool_socket_obj_t* common_hal_socketpool_socket(socketpool_socketpool_obj_ mp_raise_NotImplementedError(translate("Only IPv4 sockets supported")); } - int socknum = -1; - esp_tls_t* tcp_handle = NULL; - if (socket_type == SOCK_DGRAM || socket_type == SOCK_RAW) { - socknum = lwip_socket(addr_family, socket_type, ipproto); - } else { - tcp_handle = esp_tls_init(); - - if (tcp_handle == NULL) { - mp_raise_espidf_MemoryError(); - } - } - if (socknum < 0 && tcp_handle == NULL) { - mp_raise_RuntimeError(translate("Out of sockets")); - } - + // Consider LWIP and MbedTLS "variant" sockets to be incompatible (for now) + // The variant of the socket is determined by whether the socket is wrapped + // by SSL. If no TLS handle is set in sslcontext_wrap_socket, the first call + // of bind() or connect() will create a LWIP socket with a corresponding + // socketnum. + // TODO: move MbedTLS to its own duplicate Socket or Server API, maybe? socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t); sock->base.type = &socketpool_socket_type; - sock->num = socknum; - sock->tcp = tcp_handle; + sock->num = -1; + sock->type = socket_type; + sock->family = addr_family; + sock->ipproto = ipproto; + + sock->tls = NULL; sock->ssl_context = NULL; sock->pool = self; return sock; diff --git a/ports/esp32s2/supervisor/port.c b/ports/esp32s2/supervisor/port.c index 21a8868b5f..534f7f71bf 100644 --- a/ports/esp32s2/supervisor/port.c +++ b/ports/esp32s2/supervisor/port.c @@ -46,6 +46,7 @@ #include "common-hal/pulseio/PulseIn.h" #include "common-hal/pwmio/PWMOut.h" #include "common-hal/watchdog/WatchDogTimer.h" +#include "common-hal/socketpool/Socket.h" #include "common-hal/wifi/__init__.h" #include "supervisor/memory.h" #include "supervisor/shared/tick.h" @@ -222,6 +223,10 @@ void reset_port(void) { #if CIRCUITPY_WIFI wifi_reset(); #endif + +#if CIRCUITPY_SOCKETPOOL + socket_reset(); +#endif } void reset_to_bootloader(void) { diff --git a/shared-bindings/socketpool/Socket.c b/shared-bindings/socketpool/Socket.c index 0e6968d5f4..0074173405 100644 --- a/shared-bindings/socketpool/Socket.c +++ b/shared-bindings/socketpool/Socket.c @@ -64,94 +64,65 @@ STATIC mp_obj_t socketpool_socket___exit__(size_t n_args, const mp_obj_t *args) } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socketpool_socket___exit___obj, 4, 4, socketpool_socket___exit__); -// //| def bind(self, address: tuple) -> None: -// //| """Bind a socket to an address -// //| -// //| :param ~tuple address: tuple of (remote_address, remote_port)""" -// //| ... -// //| +//| def bind(self, address: Tuple[str, int]) -> None: +//| """Bind a socket to an address +//| +//| :param ~tuple address: tuple of (remote_address, remote_port)""" +//| ... +//| +STATIC mp_obj_t socketpool_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { + socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); -// STATIC mp_obj_t socketpool_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { -// // mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t *addr_items; + mp_obj_get_array_fixed_n(addr_in, 2, &addr_items); -// // // get address -// // uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; -// // mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); + size_t hostlen; + const char* host = mp_obj_str_get_data(addr_items[0], &hostlen); + mp_int_t port = mp_obj_get_int(addr_items[1]); -// // // check if we need to select a NIC -// // socket_select_nic(self, ip); + bool ok = common_hal_socketpool_socket_bind(self, host, hostlen, port); + if (!ok) { + mp_raise_ValueError(translate("Error: Failure to bind")); + } -// // // call the NIC to bind the socket -// // int _errno; -// // if (self->nic_type->bind(self, ip, port, &_errno) != 0) { -// // mp_raise_OSError(_errno); -// // } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_bind_obj, socketpool_socket_bind); -// return mp_const_none; -// } -// STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_bind_obj, socketpool_socket_bind); +//| def listen(self, backlog: int) -> None: +//| """Set socket to listen for incoming connections +//| +//| :param ~int backlog: length of backlog queue for waiting connetions""" +//| ... +//| +STATIC mp_obj_t socketpool_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { + socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); -// //| def listen(self, backlog: int) -> None: -// //| """Set socket to listen for incoming connections -// //| -// //| :param ~int backlog: length of backlog queue for waiting connetions""" -// //| ... -// //| + int backlog = mp_obj_get_int(backlog_in); -// STATIC mp_obj_t socketpool_socket_listen(mp_obj_t self_in, mp_obj_t backlog) { -// // mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_socketpool_socket_listen(self, backlog); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_listen_obj, socketpool_socket_listen); -// // if (self->nic == MP_OBJ_NULL) { -// // // not connected -// // // TODO I think we can listen even if not bound... -// // mp_raise_OSError(MP_ENOTCONN); -// // } +//| def accept(self) -> Tuple[Socket, Tuple[str, int]]: +//| """Accept a connection on a listening socket of type SOCK_STREAM, +//| creating a new socket of type SOCK_STREAM. +//| 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]; + uint port; -// // int _errno; -// // if (self->nic_type->listen(self, mp_obj_get_int(backlog), &_errno) != 0) { -// // mp_raise_OSError(_errno); -// // } + socketpool_socket_obj_t * sock = common_hal_socketpool_socket_accept(self, ip, &port); -// return mp_const_none; -// } -// STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_listen_obj, socketpool_socket_listen); - -// //| def accept(self) -> tuple: -// //| """Accept a connection on a listening socket of type SOCK_STREAM, -// //| creating a new socket of type SOCK_STREAM. -// //| Returns a tuple of (new_socket, remote_address)""" -// //| - -// STATIC mp_obj_t socketpool_socket_accept(mp_obj_t self_in) { -// // mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); - -// // // create new socket object -// // // starts with empty NIC so that finaliser doesn't run close() method if accept() fails -// // mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t); -// // socket2->base.type = &socket_type; -// // socket2->nic = MP_OBJ_NULL; -// // socket2->nic_type = NULL; - -// // // accept incoming connection -// // uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; -// // mp_uint_t port; -// // int _errno; -// // if (self->nic_type->accept(self, socket2, ip, &port, &_errno) != 0) { -// // mp_raise_OSError(_errno); -// // } - -// // // new socket has valid state, so set the NIC to the same as parent -// // socket2->nic = self->nic; -// // socket2->nic_type = self->nic_type; - -// // // make the return value -// // mp_obj_tuple_t *client = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); -// // client->items[0] = MP_OBJ_FROM_PTR(socket2); -// // client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); - -// return mp_const_none; -// } -// STATIC MP_DEFINE_CONST_FUN_OBJ_1(socketpool_socket_accept_obj, socketpool_socket_accept); + 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); + return mp_obj_new_tuple(2, tuple_contents); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socketpool_socket_accept_obj, socketpool_socket_accept); //| def close(self) -> None: //| """Closes this Socket and makes its resources available to its SocketPool.""" @@ -169,7 +140,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(socketpool_socket_close_obj, socketpool_socket_ //| :param ~tuple address: tuple of (remote_address, remote_port)""" //| ... //| - STATIC mp_obj_t socketpool_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -196,7 +166,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_connect_obj, socketpool_socke //| :param ~bytes bytes: some bytes to send""" //| ... //| - STATIC mp_obj_t socketpool_socket_send(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)) { @@ -216,19 +185,6 @@ 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); - -// helper function for socket_recv and socket_recv_into to handle common operations of both -// STATIC mp_int_t _socket_recv_into(mod_network_socket_obj_t *sock, byte *buf, mp_int_t len) { -// mp_int_t ret = 0; -// // int _errno; -// // mp_int_t ret = sock->nic_type->recv(sock, buf, len, &_errno); -// // if (ret == -1) { -// // mp_raise_OSError(_errno); -// // } -// return ret; -// } - - //| def recv_into(self, buffer: WriteableBuffer, bufsize: int) -> int: //| """Reads some bytes from the connected remote address, writing //| into the provided buffer. If bufsize <= len(buffer) is given, @@ -250,10 +206,10 @@ STATIC mp_obj_t socketpool_socket_recv_into(size_t n_args, const mp_obj_t *args) // Bad file number. mp_raise_OSError(MP_EBADF); } - if (!common_hal_socketpool_socket_get_connected(self)) { - // not connected - mp_raise_OSError(MP_ENOTCONN); - } + // if (!common_hal_socketpool_socket_get_connected(self)) { + // // not connected + // mp_raise_OSError(MP_ENOTCONN); + // } mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); mp_int_t len = bufinfo.len; @@ -430,9 +386,9 @@ STATIC const mp_rom_map_elem_t socketpool_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socketpool_socket_close_obj) }, { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socketpool_socket_close_obj) }, - // { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socketpool_socket_bind_obj) }, - // { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socketpool_socket_listen_obj) }, - // { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socketpool_socket_accept_obj) }, + { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socketpool_socket_bind_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socketpool_socket_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socketpool_socket_accept_obj) }, { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socketpool_socket_connect_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socketpool_socket_send_obj) }, { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socketpool_socket_sendto_obj) }, diff --git a/shared-bindings/socketpool/Socket.h b/shared-bindings/socketpool/Socket.h index 54fbe59b28..b5dceb50f4 100644 --- a/shared-bindings/socketpool/Socket.h +++ b/shared-bindings/socketpool/Socket.h @@ -32,6 +32,11 @@ extern const mp_obj_type_t socketpool_socket_type; void common_hal_socketpool_socket_settimeout(socketpool_socket_obj_t* self, mp_uint_t timeout_ms); + +bool common_hal_socketpool_socket_bind(socketpool_socket_obj_t* self, const char* host, size_t hostlen, uint8_t port); +bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t* self, int backlog); +socketpool_socket_obj_t * common_hal_socketpool_socket_accept(socketpool_socket_obj_t* self, uint8_t* ip, uint *port); + bool common_hal_socketpool_socket_connect(socketpool_socket_obj_t* self, const char* host, size_t hostlen, mp_int_t port); mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t* self, const uint8_t* buf, mp_uint_t len); mp_uint_t common_hal_socketpool_socket_recv_into(socketpool_socket_obj_t* self, const uint8_t* buf, mp_uint_t len);