Add basic error handling

This commit is contained in:
Scott Shawcroft 2020-08-18 17:06:59 -07:00
parent 9602ee6265
commit eb8b42aff1
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
18 changed files with 194 additions and 48 deletions

@ -1 +1 @@
Subproject commit 22100b252fc2eb8f51ed407949645653c4880fd9
Subproject commit e90cf7a676eddcbd9c35d2d99a0a9cd14686e2ce

View File

@ -27,6 +27,8 @@
#include "py/obj.h"
#include "py/runtime.h"
#include "bindings/espidf/__init__.h"
#include "esp-idf/components/heap/include/esp_heap_caps.h"
//| """Direct access to a few ESP-IDF details. This module *should not* include any functionality
@ -63,12 +65,41 @@ STATIC mp_obj_t espidf_heap_caps_get_largest_free_block(void) {
}
MP_DEFINE_CONST_FUN_OBJ_0(espidf_heap_caps_get_largest_free_block_obj, espidf_heap_caps_get_largest_free_block);
//| class MemoryError(MemoryError):
//| """Raised when an ESP IDF memory allocation fails."""
//| ...
//|
NORETURN void mp_raise_espidf_MemoryError(void) {
nlr_raise(mp_obj_new_exception(&mp_type_espidf_MemoryError));
}
void espidf_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS;
bool is_subclass = kind & PRINT_EXC_SUBCLASS;
if (!is_subclass && (k == PRINT_EXC)) {
mp_print_str(print, qstr_str(MP_OBJ_QSTR_VALUE(MP_QSTR_espidf)));
mp_print_str(print, ".");
}
mp_obj_exception_print(print, o_in, kind);
}
const mp_obj_type_t mp_type_espidf_MemoryError = {
{ &mp_type_type },
.name = MP_QSTR_MemoryError,
.print = espidf_exception_print,
.make_new = mp_obj_exception_make_new,
.attr = mp_obj_exception_attr,
.parent = &mp_type_MemoryError,
};
STATIC const mp_rom_map_elem_t espidf_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_espidf) },
{ MP_ROM_QSTR(MP_QSTR_heap_caps_get_total_size), MP_ROM_PTR(&espidf_heap_caps_get_total_size_obj)},
{ MP_ROM_QSTR(MP_QSTR_heap_caps_get_free_size), MP_ROM_PTR(&espidf_heap_caps_get_free_size_obj)},
{ MP_ROM_QSTR(MP_QSTR_heap_caps_get_largest_free_block), MP_ROM_PTR(&espidf_heap_caps_get_largest_free_block_obj)},
{ MP_ROM_QSTR(MP_QSTR_MemoryError), MP_ROM_PTR(&mp_type_espidf_MemoryError) },
};
STATIC MP_DEFINE_CONST_DICT(espidf_module_globals, espidf_module_globals_table);

View File

@ -0,0 +1,34 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ESP32S2_BINDINGS_ESPIDF___INIT___H
#define MICROPY_INCLUDED_ESP32S2_BINDINGS_ESPIDF___INIT___H
extern const mp_obj_type_t mp_type_espidf_MemoryError;
NORETURN void mp_raise_espidf_MemoryError(void);
#endif // MICROPY_INCLUDED_ESP32S2_BINDINGS_ESPIDF___INIT___H

View File

@ -26,6 +26,9 @@
#include "shared-bindings/socketpool/Socket.h"
#include "py/mperrno.h"
#include "py/runtime.h"
void common_hal_socketpool_socket_settimeout(socketpool_socket_obj_t* self, mp_uint_t timeout_ms) {
self->timeout_ms = timeout_ms;
}
@ -40,14 +43,26 @@ bool common_hal_socketpool_socket_connect(socketpool_socket_obj_t* self, const c
tls_config = &self->ssl_context->ssl_config;
}
int result = esp_tls_conn_new_sync(host, hostlen, port, tls_config, self->tcp);
return result >= 0;
self->connected = result >= 0;
if (result < 0) {
int esp_tls_code;
esp_tls_get_and_clear_last_error(self->tcp->error_handle, &esp_tls_code, NULL);
// mp_raise_espidf_MemoryError
mp_raise_OSError_msg_varg(translate("Unhandled ESP TLS error %d"), esp_tls_code);
}
return self->connected;
}
bool common_hal_socketpool_socket_get_connected(socketpool_socket_obj_t* self) {
return self->connected;
}
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);
if (sent < 0) {
// raise an error
mp_raise_OSError(MP_ENOTCONN);
}
return sent;
}
@ -57,14 +72,18 @@ mp_uint_t common_hal_socketpool_socket_recv_into(socketpool_socket_obj_t* self,
if (received == 0) {
// socket closed
common_hal_socketpool_socket_close(self);
}
if (received < 0) {
// raise an error
mp_raise_BrokenPipeError();
}
return received;
}
void common_hal_socketpool_socket_close(socketpool_socket_obj_t* self) {
if (self->connected) {
self->connected = false;
}
if (self->tcp != NULL) {
int status = esp_tls_conn_destroy(self->tcp);
@ -74,3 +93,7 @@ void common_hal_socketpool_socket_close(socketpool_socket_obj_t* self) {
self->tcp = NULL;
}
}
bool common_hal_socketpool_socket_get_closed(socketpool_socket_obj_t* self) {
return self->tcp == NULL;
}

View File

@ -37,6 +37,7 @@
typedef struct {
mp_obj_base_t base;
int num;
bool connected;
esp_tls_t* tcp;
ssl_sslcontext_obj_t* ssl_context;
socketpool_socketpool_obj_t* pool;

View File

@ -27,9 +27,19 @@
#include "shared-bindings/socketpool/SocketPool.h"
#include "py/runtime.h"
#include "shared-bindings/wifi/__init__.h"
#include "esp-idf/components/lwip/lwip/src/include/lwip/netdb.h"
#include "bindings/espidf/__init__.h"
void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t* self, mp_obj_t radio) {
if (radio != MP_OBJ_FROM_PTR(&common_hal_wifi_radio_obj)) {
mp_raise_ValueError(translate("SocketPool can only be used with wifi.radio."));
}
}
socketpool_socket_obj_t* common_hal_socketpool_socket(socketpool_socketpool_obj_t* self,
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type) {
@ -52,12 +62,21 @@ socketpool_socket_obj_t* common_hal_socketpool_socket(socketpool_socketpool_obj_
socket_type = SOCK_RAW;
}
if (socket_type == SOCK_DGRAM || socket_type == SOCK_RAW ||
addr_family == AF_INET6 || ipproto == IPPROTO_IPV6) {
mp_raise_NotImplementedError(translate("Only IPv4 SOCK_STREAM 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);
// 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"));

View File

@ -726,6 +726,9 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_NameError), MP_ROM_PTR(&mp_type_NameError) },
{ MP_ROM_QSTR(MP_QSTR_NotImplementedError), MP_ROM_PTR(&mp_type_NotImplementedError) },
{ MP_ROM_QSTR(MP_QSTR_OSError), MP_ROM_PTR(&mp_type_OSError) },
{ MP_ROM_QSTR(MP_QSTR_TimeoutError), MP_ROM_PTR(&mp_type_TimeoutError) },
{ MP_ROM_QSTR(MP_QSTR_ConnectionError), MP_ROM_PTR(&mp_type_ConnectionError) },
{ MP_ROM_QSTR(MP_QSTR_BrokenPipeError), MP_ROM_PTR(&mp_type_BrokenPipeError) },
{ MP_ROM_QSTR(MP_QSTR_OverflowError), MP_ROM_PTR(&mp_type_OverflowError) },
{ MP_ROM_QSTR(MP_QSTR_RuntimeError), MP_ROM_PTR(&mp_type_RuntimeError) },
#if MICROPY_PY_ASYNC_AWAIT

View File

@ -604,6 +604,8 @@ extern const mp_obj_type_t mp_type_NameError;
extern const mp_obj_type_t mp_type_NotImplementedError;
extern const mp_obj_type_t mp_type_OSError;
extern const mp_obj_type_t mp_type_TimeoutError;
extern const mp_obj_type_t mp_type_ConnectionError;
extern const mp_obj_type_t mp_type_BrokenPipeError;
extern const mp_obj_type_t mp_type_OverflowError;
extern const mp_obj_type_t mp_type_RuntimeError;
extern const mp_obj_type_t mp_type_StopAsyncIteration;

View File

@ -283,14 +283,16 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
*/
MP_DEFINE_EXCEPTION(OSError, Exception)
MP_DEFINE_EXCEPTION(TimeoutError, OSError)
/*
MP_DEFINE_EXCEPTION(BlockingIOError, OSError)
MP_DEFINE_EXCEPTION(ChildProcessError, OSError)
MP_DEFINE_EXCEPTION(ConnectionError, OSError)
MP_DEFINE_EXCEPTION(BrokenPipeError, ConnectionError)
/*
MP_DEFINE_EXCEPTION(ConnectionAbortedError, ConnectionError)
MP_DEFINE_EXCEPTION(ConnectionRefusedError, ConnectionError)
MP_DEFINE_EXCEPTION(ConnectionResetError, ConnectionError)
*/
/*
MP_DEFINE_EXCEPTION(BlockingIOError, OSError)
MP_DEFINE_EXCEPTION(ChildProcessError, OSError)
MP_DEFINE_EXCEPTION(InterruptedError, OSError)
MP_DEFINE_EXCEPTION(IsADirectoryError, OSError)
MP_DEFINE_EXCEPTION(NotADirectoryError, OSError)

View File

@ -1602,6 +1602,10 @@ NORETURN void mp_raise_OSError_msg_varg(const compressed_string_t *fmt, ...) {
va_end(argptr);
}
NORETURN void mp_raise_BrokenPipeError(void) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_BrokenPipeError, MP_OBJ_NEW_SMALL_INT(MP_EPIPE)));
}
NORETURN void mp_raise_NotImplementedError(const compressed_string_t *msg) {
mp_raise_msg(&mp_type_NotImplementedError, msg);
}

View File

@ -166,6 +166,7 @@ NORETURN void mp_raise_OSError(int errno_);
NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str);
NORETURN void mp_raise_OSError_msg(const compressed_string_t *msg);
NORETURN void mp_raise_OSError_msg_varg(const compressed_string_t *fmt, ...);
NORETURN void mp_raise_BrokenPipeError(void);
NORETURN void mp_raise_NotImplementedError(const compressed_string_t *msg);
NORETURN void mp_raise_NotImplementedError_varg(const compressed_string_t *fmt, ...);
NORETURN void mp_raise_OverflowError_varg(const compressed_string_t *fmt, ...);

View File

@ -25,22 +25,24 @@
* THE SOFTWARE.
*/
#include "shared-bindings/ipaddress/IPv4Address.h"
#include <string.h>
#include <stdio.h>
#include "py/objproperty.h"
#include "py/objstr.h"
#include "py/runtime.h"
#include "shared-bindings/ipaddress/IPv4Address.h"
#include "shared-bindings/ipaddress/__init__.h"
//| class IPv4Address:
//| """Encapsulates an IPv4 address."""
//|
//| def __init__(self, address: Union[str, int]) -> None:
//| """Create a new Address object encapsulating the address value.
//| def __init__(self, address: Union[str, bytes]) -> None:
//| """Create a new IPv4Address object encapsulating the address value.
//|
//| The value itself can be one of:"""
//| The value itself can either be bytes or a string formatted address.""
//| ...
//|
STATIC mp_obj_t ipaddress_ipv4address_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
@ -52,17 +54,33 @@ STATIC mp_obj_t ipaddress_ipv4address_make_new(const mp_obj_type_t *type, size_t
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
ipaddress_ipv4address_obj_t *self = m_new_obj(ipaddress_ipv4address_obj_t);
self->base.type = &ipaddress_ipv4address_type;
const mp_obj_t address = args[ARG_address].u_obj;
uint32_t value;
uint8_t* buf = NULL;
if (mp_obj_get_int_maybe(address, (mp_int_t*) &value)) {
// We're done.
buf = (uint8_t*) value;
} else if (MP_OBJ_IS_STR(address)) {
GET_STR_DATA_LEN(address, str_data, str_len);
if (!ipaddress_parse_ipv4address((const char*) str_data, str_len, &value)) {
mp_raise_ValueError(translate("Not a valid IP string."));
}
} else {
mp_buffer_info_t buf_info;
mp_get_buffer_raise(address, &buf_info, MP_BUFFER_READ);
if (mp_get_buffer(address, &buf_info, MP_BUFFER_READ)) {
if (buf_info.len != 4) {
mp_raise_ValueError_varg(translate("Address must be %d bytes long"), 4);
}
buf = buf_info.buf;
}
}
common_hal_ipaddress_ipv4address_construct(self, buf_info.buf, buf_info.len);
ipaddress_ipv4address_obj_t *self = m_new_obj(ipaddress_ipv4address_obj_t);
self->base.type = &ipaddress_ipv4address_type;
common_hal_ipaddress_ipv4address_construct(self, buf, 4);
return MP_OBJ_FROM_PTR(self);
}
@ -108,7 +126,7 @@ const mp_obj_property_t ipaddress_ipv4address_version_obj = {
(mp_obj_t)&mp_const_none_obj},
};
//| def __eq__(self, other: Address) -> bool:
//| def __eq__(self, other: IPv4Address) -> bool:
//| """Two Address objects are equal if their addresses and address types are equal."""
//| ...
//|
@ -133,7 +151,7 @@ STATIC mp_obj_t ipaddress_ipv4address_binary_op(mp_binary_op_t op, mp_obj_t lhs_
}
//| def __hash__(self) -> int:
//| """Returns a hash for the Address data."""
//| """Returns a hash for the IPv4Address data."""
//| ...
//|
STATIC mp_obj_t ipaddress_ipv4address_unary_op(mp_unary_op_t op, mp_obj_t self_in) {

View File

@ -57,7 +57,7 @@
//|
STATIC mp_obj_t socketpool_socket___exit__(size_t n_args, const mp_obj_t *args) {
(void)n_args;
// common_hal_pulseio_pwmout_deinit(args[0]);
common_hal_socketpool_socket_close(args[0]);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socketpool_socket___exit___obj, 4, 4, socketpool_socket___exit__);
@ -197,15 +197,18 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_connect_obj, socketpool_socke
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 (self->nic == MP_OBJ_NULL) {
// // not connected
// mp_raise_OSError(MP_EPIPE);
// }
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);
mp_int_t ret = common_hal_socketpool_socket_send(self, bufinfo.buf, bufinfo.len);
if (ret == -1) {
mp_raise_OSError(0);
mp_raise_BrokenPipeError();
}
return mp_obj_new_int_from_uint(ret);
}
@ -241,10 +244,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_send_obj, socketpool_socket_s
STATIC mp_obj_t socketpool_socket_recv_into(size_t n_args, const mp_obj_t *args) {
socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(args[0]);
// if (self->nic == MP_OBJ_NULL) {
// // not connected
// mp_raise_OSError(MP_ENOTCONN);
// }
if (common_hal_socketpool_socket_get_closed(self)) {
// Bad file number.
mp_raise_OSError(MP_EBADF);
}
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;

View File

@ -36,5 +36,7 @@ bool common_hal_socketpool_socket_connect(socketpool_socket_obj_t* self, const c
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);
void common_hal_socketpool_socket_close(socketpool_socket_obj_t* self);
bool common_hal_socketpool_socket_get_closed(socketpool_socket_obj_t* self);
bool common_hal_socketpool_socket_get_connected(socketpool_socket_obj_t* self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SOCKETPOOL_SOCKET_H

View File

@ -38,15 +38,21 @@
#include "shared-bindings/socketpool/SocketPool.h"
//| class SocketPool:
//| """A pool of socket resources available for the given radio. Only one
//| SocketPool can be created for each radio.
//|
//| SocketPool should be used in place of CPython's socket which provides
//| a pool of sockets provided by the underlying OS."""
//|
STATIC mp_obj_t socketpool_socketpool_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
mp_arg_check_num(n_args, kw_args, 0, 4, false);
mp_arg_check_num(n_args, kw_args, 1, 1, false);
socketpool_socketpool_obj_t *s = m_new_obj_with_finaliser(socketpool_socketpool_obj_t);
s->base.type = &socketpool_socketpool_type;
mp_obj_t radio = args[1];
// common_hal_socketpool_socketpool_construct(s, );
common_hal_socketpool_socketpool_construct(s, radio);
return MP_OBJ_FROM_PTR(s);
}

View File

@ -44,6 +44,8 @@ typedef enum {
SOCKETPOOL_AF_INET6
} socketpool_socketpool_addressfamily_t;
void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t* self, mp_obj_t radio);
socketpool_socket_obj_t* common_hal_socketpool_socket(socketpool_socketpool_obj_t* self,
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type);

View File

@ -3,8 +3,7 @@
*
* The MIT License (MIT)
*
* SPDX-FileCopyrightText: Copyright (c) 2014 Damien P. George
* 2018 Nick Moore for Adafruit Industries
* SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -36,6 +35,9 @@
#include "shared-bindings/ssl/SSLContext.h"
//| class SSLContext:
//| """Settings related to SSL that can be applied to a socket by wrapping it.
//| This is useful to provide SSL certificates to specific connections
//| rather than all of them."""
//|
STATIC mp_obj_t ssl_sslcontext_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {

View File

@ -33,17 +33,6 @@
extern const mp_obj_type_t ssl_sslcontext_type;
// typedef enum {
// SOCKETPOOL_SOCK_STREAM,
// SOCKETPOOL_SOCK_DGRAM,
// SOCKETPOOL_SOCK_RAW
// } socketpool_socketpool_sock_t;
// typedef enum {
// SOCKETPOOL_AF_INET,
// SOCKETPOOL_AF_INET6
// } socketpool_socketpool_addressfamily_t;
void common_hal_ssl_sslcontext_construct(ssl_sslcontext_obj_t* self);
socketpool_socket_obj_t* common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t* self,