extmod/modnetwork: Use a type protocol to implement NIC functions.

This was previously implemented by adding additional members to the
mp_obj_type_t defined for each NIC, which is difficult to do cleanly with
the new object type slots mechanism. The way this works is also not
supported on GCC 8.x and below.

Instead replace it with the type protocol, which is a much simpler way of
achieving the same thing.

This affects the WizNet (in non-LWIP mode) and Nina NIC drivers.

This work was funded through GitHub Sponsors.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This commit is contained in:
Jim Mussared 2022-12-14 16:29:30 +11:00 committed by Damien George
parent 7f71057a89
commit 5f8f32f917
7 changed files with 55 additions and 71 deletions

View File

@ -77,7 +77,7 @@ mp_obj_t mod_network_find_nic(const uint8_t *ip) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i];
// TODO check IP suitability here
// mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic);
// mod_network_nic_protocol_t *nic_protocol = (mod_network_nic_protocol_t *)MP_OBJ_TYPE_GET_SLOT(mp_obj_get_type(nic), protocol);
return nic;
}

View File

@ -61,10 +61,7 @@ mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_o
struct _mod_network_socket_obj_t;
typedef struct _mod_network_nic_type_t {
// Ensure that this struct is big enough to hold any type size.
mp_obj_full_type_t base;
typedef struct _mod_network_nic_protocol_t {
// API for non-socket operations
int (*gethostbyname)(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *ip_out);
@ -82,12 +79,12 @@ typedef struct _mod_network_nic_type_t {
int (*setsockopt)(struct _mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno);
int (*settimeout)(struct _mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno);
int (*ioctl)(struct _mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno);
} mod_network_nic_type_t;
} mod_network_nic_protocol_t;
typedef struct _mod_network_socket_obj_t {
mp_obj_base_t base;
mp_obj_t nic;
mod_network_nic_type_t *nic_type;
mod_network_nic_protocol_t *nic_protocol;
uint32_t domain : 5;
uint32_t type : 5;
uint32_t proto : 5;

View File

@ -57,7 +57,7 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t
mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t);
s->base.type = &socket_type;
s->nic = MP_OBJ_NULL;
s->nic_type = NULL;
s->nic_protocol = NULL;
s->domain = MOD_NETWORK_AF_INET;
s->type = MOD_NETWORK_SOCK_STREAM;
s->proto = 0;
@ -86,17 +86,17 @@ STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) {
if (self->nic == MP_OBJ_NULL) {
// select NIC based on IP
self->nic = mod_network_find_nic(ip);
self->nic_type = (mod_network_nic_type_t *)mp_obj_get_type(self->nic);
self->nic_protocol = (mod_network_nic_protocol_t *)MP_OBJ_TYPE_GET_SLOT(mp_obj_get_type(self->nic), protocol);
// call the NIC to open the socket
int _errno;
if (self->nic_type->socket(self, &_errno) != 0) {
if (self->nic_protocol->socket(self, &_errno) != 0) {
mp_raise_OSError(_errno);
}
#if MICROPY_PY_USOCKET_EXTENDED_STATE
// if a timeout was set before binding a NIC, call settimeout to reset it
if (self->timeout != -1 && self->nic_type->settimeout(self, self->timeout, &_errno) != 0) {
if (self->timeout != -1 && self->nic_protocol->settimeout(self, self->timeout, &_errno) != 0) {
mp_raise_OSError(_errno);
}
#endif
@ -116,7 +116,7 @@ STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
// call the NIC to bind the socket
int _errno;
if (self->nic_type->bind(self, ip, port, &_errno) != 0) {
if (self->nic_protocol->bind(self, ip, port, &_errno) != 0) {
mp_raise_OSError(_errno);
}
@ -141,7 +141,7 @@ STATIC mp_obj_t socket_listen(size_t n_args, const mp_obj_t *args) {
}
int _errno;
if (self->nic_type->listen(self, backlog, &_errno) != 0) {
if (self->nic_protocol->listen(self, backlog, &_errno) != 0) {
mp_raise_OSError(_errno);
}
@ -166,7 +166,7 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
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;
socket2->nic_protocol = NULL;
// set the same address family, socket type and protocol as parent
socket2->domain = self->domain;
@ -185,13 +185,13 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
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) {
if (self->nic_protocol->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;
socket2->nic_protocol = self->nic_protocol;
// make the return value
mp_obj_tuple_t *client = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
@ -215,7 +215,7 @@ STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
// call the NIC to connect the socket
int _errno;
if (self->nic_type->connect(self, ip, port, &_errno) != 0) {
if (self->nic_protocol->connect(self, ip, port, &_errno) != 0) {
mp_raise_OSError(_errno);
}
@ -236,7 +236,7 @@ STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
int _errno;
mp_uint_t ret = self->nic_type->send(self, bufinfo.buf, bufinfo.len, &_errno);
mp_uint_t ret = self->nic_protocol->send(self, bufinfo.buf, bufinfo.len, &_errno);
if (ret == -1) {
mp_raise_OSError(_errno);
}
@ -256,7 +256,7 @@ STATIC mp_obj_t socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
int _errno;
mp_uint_t ret = 0;
if (self->timeout == 0) {
ret = self->nic_type->send(self, bufinfo.buf, bufinfo.len, &_errno);
ret = self->nic_protocol->send(self, bufinfo.buf, bufinfo.len, &_errno);
if (ret == -1) {
mp_raise_OSError(_errno);
} else if (bufinfo.len > ret) {
@ -266,7 +266,7 @@ STATIC mp_obj_t socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
// TODO: In CPython3.5, socket timeout should apply to the
// entire sendall() operation, not to individual send() chunks.
while (bufinfo.len != 0) {
ret = self->nic_type->send(self, bufinfo.buf, bufinfo.len, &_errno);
ret = self->nic_protocol->send(self, bufinfo.buf, bufinfo.len, &_errno);
if (ret == -1) {
mp_raise_OSError(_errno);
}
@ -289,7 +289,7 @@ STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
vstr_t vstr;
vstr_init_len(&vstr, len);
int _errno;
mp_uint_t ret = self->nic_type->recv(self, (byte *)vstr.buf, len, &_errno);
mp_uint_t ret = self->nic_protocol->recv(self, (byte *)vstr.buf, len, &_errno);
if (ret == -1) {
mp_raise_OSError(_errno);
}
@ -318,7 +318,7 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_
// call the NIC to sendto
int _errno;
mp_int_t ret = self->nic_type->sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno);
mp_int_t ret = self->nic_protocol->sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno);
if (ret == -1) {
mp_raise_OSError(_errno);
}
@ -339,7 +339,7 @@ STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
byte ip[4];
mp_uint_t port;
int _errno;
mp_int_t ret = self->nic_type->recvfrom(self, (byte *)vstr.buf, vstr.len, ip, &port, &_errno);
mp_int_t ret = self->nic_protocol->recvfrom(self, (byte *)vstr.buf, vstr.len, ip, &port, &_errno);
if (ret == -1) {
mp_raise_OSError(_errno);
}
@ -389,7 +389,7 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
}
int _errno;
if (self->nic_type->setsockopt(self, level, opt, optval, optlen, &_errno) != 0) {
if (self->nic_protocol->setsockopt(self, level, opt, optval, optlen, &_errno) != 0) {
mp_raise_OSError(_errno);
}
@ -429,7 +429,7 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
#endif
} else {
int _errno;
if (self->nic_type->settimeout(self, timeout, &_errno) != 0) {
if (self->nic_protocol->settimeout(self, timeout, &_errno) != 0) {
mp_raise_OSError(_errno);
}
}
@ -477,7 +477,7 @@ mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode)
if (self->nic == MP_OBJ_NULL) {
return MP_STREAM_ERROR;
}
mp_int_t ret = self->nic_type->recv(self, (byte *)buf, size, errcode);
mp_int_t ret = self->nic_protocol->recv(self, (byte *)buf, size, errcode);
if (ret < 0) {
ret = MP_STREAM_ERROR;
}
@ -489,7 +489,7 @@ mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *e
if (self->nic == MP_OBJ_NULL) {
return MP_STREAM_ERROR;
}
mp_int_t ret = self->nic_type->send(self, buf, size, errcode);
mp_int_t ret = self->nic_protocol->send(self, buf, size, errcode);
if (ret < 0) {
ret = MP_STREAM_ERROR;
}
@ -500,7 +500,7 @@ mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *
mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (request == MP_STREAM_CLOSE) {
if (self->nic != MP_OBJ_NULL) {
self->nic_type->close(self);
self->nic_protocol->close(self);
self->nic = MP_OBJ_NULL;
}
self->state = MOD_NETWORK_SS_CLOSED;
@ -519,7 +519,7 @@ mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *
*errcode = MP_EINVAL;
return MP_STREAM_ERROR;
}
return self->nic_type->ioctl(self, request, arg, errcode);
return self->nic_protocol->ioctl(self, request, arg, errcode);
}
STATIC const mp_stream_p_t socket_stream_p = {
@ -589,9 +589,9 @@ STATIC mp_obj_t mod_usocket_getaddrinfo(size_t n_args, const mp_obj_t *args) {
// find a NIC that can do a name lookup
for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i];
mod_network_nic_type_t *nic_type = (mod_network_nic_type_t *)mp_obj_get_type(nic);
if (nic_type->gethostbyname != NULL) {
int ret = nic_type->gethostbyname(nic, host, hlen, out_ip);
mod_network_nic_protocol_t *nic_protocol = (mod_network_nic_protocol_t *)MP_OBJ_TYPE_GET_SLOT(mp_obj_get_type(nic), protocol);
if (nic_protocol->gethostbyname != NULL) {
int ret = nic_protocol->gethostbyname(nic, host, hlen, out_ip);
if (ret != 0) {
mp_raise_OSError(ret);
}

View File

@ -77,7 +77,7 @@ typedef struct _nina_obj_t {
#define debug_printf(...) // mp_printf(&mp_plat_print, __VA_ARGS__)
static uint16_t bind_port = BIND_PORT_RANGE_MIN;
const mod_network_nic_type_t mod_network_nic_type_nina;
const mp_obj_type_t mod_network_nic_type_nina;
static nina_obj_t network_nina_wl_sta = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_STA_IF};
static nina_obj_t network_nina_wl_ap = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_AP_IF};
static mp_sched_node_t mp_wifi_sockpoll_node;
@ -798,7 +798,7 @@ STATIC int network_ninaw10_socket_ioctl(mod_network_socket_obj_t *socket, mp_uin
return ret;
}
static const mp_rom_map_elem_t nina_locals_dict_table[] = {
STATIC const mp_rom_map_elem_t nina_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_ninaw10_active_obj) },
{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_ninaw10_scan_obj) },
{ MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_ninaw10_connect_obj) },
@ -817,18 +817,9 @@ static const mp_rom_map_elem_t nina_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_WPA_PSK), MP_ROM_INT(NINA_SEC_WPA_PSK) },
};
static MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table);
STATIC MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table);
STATIC MP_DEFINE_CONST_OBJ_FULL_TYPE(
mod_network_nic_type_nina_base,
MP_QSTR_nina,
MP_TYPE_FLAG_NONE,
make_new, network_ninaw10_make_new,
locals_dict, &nina_locals_dict
);
const mod_network_nic_type_t mod_network_nic_type_nina = {
.base = mod_network_nic_type_nina_base,
STATIC const mod_network_nic_protocol_t mod_network_nic_protocol_nina = {
.gethostbyname = network_ninaw10_gethostbyname,
.socket = network_ninaw10_socket_socket,
.close = network_ninaw10_socket_close,
@ -845,6 +836,15 @@ const mod_network_nic_type_t mod_network_nic_type_nina = {
.ioctl = network_ninaw10_socket_ioctl,
};
MP_DEFINE_CONST_OBJ_TYPE(
mod_network_nic_type_nina,
MP_QSTR_nina,
MP_TYPE_FLAG_NONE,
make_new, network_ninaw10_make_new,
locals_dict, &nina_locals_dict,
protocol, &mod_network_nic_protocol_nina
);
MP_REGISTER_ROOT_POINTER(struct _machine_spi_obj_t *mp_wifi_spi);
MP_REGISTER_ROOT_POINTER(struct _machine_timer_obj_t *mp_wifi_timer);
MP_REGISTER_ROOT_POINTER(struct _mp_obj_list_t *mp_wifi_sockpoll_list);

View File

@ -1017,24 +1017,9 @@ STATIC const mp_rom_map_elem_t wiznet5k_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table);
#if WIZNET5K_WITH_LWIP_STACK
MP_DEFINE_CONST_OBJ_TYPE(
mod_network_nic_type_wiznet5k,
MP_QSTR_WIZNET5K,
MP_TYPE_FLAG_NONE,
make_new, wiznet5k_make_new,
locals_dict, &wiznet5k_locals_dict
);
#define NIC_TYPE_WIZNET_PROTOCOL
#else // WIZNET5K_PROVIDED_STACK
STATIC MP_DEFINE_CONST_OBJ_FULL_TYPE(
mod_network_nic_type_wiznet5k_base,
MP_QSTR_WIZNET5K,
MP_TYPE_FLAG_NONE,
make_new, wiznet5k_make_new,
locals_dict, &wiznet5k_locals_dict
);
const mod_network_nic_type_t mod_network_nic_type_wiznet5k = {
.base = mod_network_nic_type_wiznet5k_base,
const mod_network_nic_protocol_t mod_network_nic_protocol_wiznet = {
.gethostbyname = wiznet5k_gethostbyname,
.socket = wiznet5k_socket_socket,
.close = wiznet5k_socket_close,
@ -1050,6 +1035,16 @@ const mod_network_nic_type_t mod_network_nic_type_wiznet5k = {
.settimeout = wiznet5k_socket_settimeout,
.ioctl = wiznet5k_socket_ioctl,
};
#define NIC_TYPE_WIZNET_PROTOCOL protocol, &mod_network_nic_protocol_wiznet,
#endif
MP_DEFINE_CONST_OBJ_TYPE(
mod_network_nic_type_wiznet5k,
MP_QSTR_WIZNET5K,
MP_TYPE_FLAG_NONE,
make_new, wiznet5k_make_new,
NIC_TYPE_WIZNET_PROTOCOL
locals_dict, &wiznet5k_locals_dict
);
#endif // MICROPY_PY_NETWORK_WIZNET5K

View File

@ -176,18 +176,14 @@ extern const struct _mp_obj_type_t mp_network_cyw43_type;
#ifndef MICROPY_PY_USOCKET_EXTENDED_STATE
#define MICROPY_PY_USOCKET_EXTENDED_STATE (1)
#endif
extern const struct _mod_network_nic_type_t mod_network_nic_type_nina;
extern const struct _mp_obj_type_t mod_network_nic_type_nina;
#define MICROPY_HW_NIC_NINAW10 { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mod_network_nic_type_nina) },
#else
#define MICROPY_HW_NIC_NINAW10
#endif
#if MICROPY_PY_NETWORK_WIZNET5K
#if MICROPY_PY_LWIP
extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k;
#else
extern const struct _mod_network_nic_type_t mod_network_nic_type_wiznet5k;
#endif
#define MICROPY_HW_NIC_WIZNET5K { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) },
#else
#define MICROPY_HW_NIC_WIZNET5K

View File

@ -191,11 +191,7 @@ extern const struct _mp_obj_type_t mp_network_cyw43_type;
#endif
#if MICROPY_PY_NETWORK_WIZNET5K
#if MICROPY_PY_LWIP
extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k;
#else
extern const struct _mod_network_nic_type_t mod_network_nic_type_wiznet5k;
#endif
#define MICROPY_HW_NIC_WIZNET5K { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) },
#else
#define MICROPY_HW_NIC_WIZNET5K