mirror of
https://github.com/micropython/micropython.git
synced 2026-01-04 11:10:14 +01:00
esp32/modsocket: Correctly handle poll/read of unconnected TCP socket.
For an unconnected TCP socket, poll should return WR|HUP and read should raise ENOTCONN. This is implemented by this commit and now the following tests pass on esp32: extmod/usocket_tcp_basic.py, net_hosted/connect_poll.py. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
@@ -59,13 +59,19 @@
|
|||||||
#define MDNS_QUERY_TIMEOUT_MS (5000)
|
#define MDNS_QUERY_TIMEOUT_MS (5000)
|
||||||
#define MDNS_LOCAL_SUFFIX ".local"
|
#define MDNS_LOCAL_SUFFIX ".local"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SOCKET_STATE_NEW,
|
||||||
|
SOCKET_STATE_CONNECTED,
|
||||||
|
SOCKET_STATE_PEER_CLOSED,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct _socket_obj_t {
|
typedef struct _socket_obj_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
int fd;
|
int fd;
|
||||||
uint8_t domain;
|
uint8_t domain;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t proto;
|
uint8_t proto;
|
||||||
bool peer_closed;
|
uint8_t state;
|
||||||
unsigned int retries;
|
unsigned int retries;
|
||||||
#if MICROPY_PY_USOCKET_EVENTS
|
#if MICROPY_PY_USOCKET_EVENTS
|
||||||
mp_obj_t events_callback;
|
mp_obj_t events_callback;
|
||||||
@@ -254,7 +260,6 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, siz
|
|||||||
sock->domain = AF_INET;
|
sock->domain = AF_INET;
|
||||||
sock->type = SOCK_STREAM;
|
sock->type = SOCK_STREAM;
|
||||||
sock->proto = 0;
|
sock->proto = 0;
|
||||||
sock->peer_closed = false;
|
|
||||||
if (n_args > 0) {
|
if (n_args > 0) {
|
||||||
sock->domain = mp_obj_get_int(args[0]);
|
sock->domain = mp_obj_get_int(args[0]);
|
||||||
if (n_args > 1) {
|
if (n_args > 1) {
|
||||||
@@ -265,6 +270,8 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, siz
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sock->state = sock->type == SOCK_STREAM ? SOCKET_STATE_NEW : SOCKET_STATE_CONNECTED;
|
||||||
|
|
||||||
sock->fd = lwip_socket(sock->domain, sock->type, sock->proto);
|
sock->fd = lwip_socket(sock->domain, sock->type, sock->proto);
|
||||||
if (sock->fd < 0) {
|
if (sock->fd < 0) {
|
||||||
mp_raise_OSError(errno);
|
mp_raise_OSError(errno);
|
||||||
@@ -278,6 +285,7 @@ STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) {
|
|||||||
socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
|
socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
|
||||||
struct addrinfo *res;
|
struct addrinfo *res;
|
||||||
_socket_getaddrinfo(arg1, &res);
|
_socket_getaddrinfo(arg1, &res);
|
||||||
|
self->state = SOCKET_STATE_CONNECTED;
|
||||||
int r = lwip_bind(self->fd, res->ai_addr, res->ai_addrlen);
|
int r = lwip_bind(self->fd, res->ai_addr, res->ai_addrlen);
|
||||||
lwip_freeaddrinfo(res);
|
lwip_freeaddrinfo(res);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@@ -290,6 +298,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
|
|||||||
STATIC mp_obj_t socket_listen(const mp_obj_t arg0, const mp_obj_t arg1) {
|
STATIC mp_obj_t socket_listen(const mp_obj_t arg0, const mp_obj_t arg1) {
|
||||||
socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
|
socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
|
||||||
int backlog = mp_obj_get_int(arg1);
|
int backlog = mp_obj_get_int(arg1);
|
||||||
|
self->state = SOCKET_STATE_CONNECTED;
|
||||||
int r = lwip_listen(self->fd, backlog);
|
int r = lwip_listen(self->fd, backlog);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
mp_raise_OSError(errno);
|
mp_raise_OSError(errno);
|
||||||
@@ -332,7 +341,7 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) {
|
|||||||
sock->domain = self->domain;
|
sock->domain = self->domain;
|
||||||
sock->type = self->type;
|
sock->type = self->type;
|
||||||
sock->proto = self->proto;
|
sock->proto = self->proto;
|
||||||
sock->peer_closed = false;
|
sock->state = SOCKET_STATE_CONNECTED;
|
||||||
_socket_settimeout(sock, UINT64_MAX);
|
_socket_settimeout(sock, UINT64_MAX);
|
||||||
|
|
||||||
// make the return value
|
// make the return value
|
||||||
@@ -351,6 +360,7 @@ STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) {
|
|||||||
struct addrinfo *res;
|
struct addrinfo *res;
|
||||||
_socket_getaddrinfo(arg1, &res);
|
_socket_getaddrinfo(arg1, &res);
|
||||||
MP_THREAD_GIL_EXIT();
|
MP_THREAD_GIL_EXIT();
|
||||||
|
self->state = SOCKET_STATE_CONNECTED;
|
||||||
int r = lwip_connect(self->fd, res->ai_addr, res->ai_addrlen);
|
int r = lwip_connect(self->fd, res->ai_addr, res->ai_addrlen);
|
||||||
MP_THREAD_GIL_ENTER();
|
MP_THREAD_GIL_ENTER();
|
||||||
lwip_freeaddrinfo(res);
|
lwip_freeaddrinfo(res);
|
||||||
@@ -471,11 +481,17 @@ STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size,
|
|||||||
struct sockaddr *from, socklen_t *from_len, int *errcode) {
|
struct sockaddr *from, socklen_t *from_len, int *errcode) {
|
||||||
socket_obj_t *sock = MP_OBJ_TO_PTR(self_in);
|
socket_obj_t *sock = MP_OBJ_TO_PTR(self_in);
|
||||||
|
|
||||||
|
// A new socket cannot be read from.
|
||||||
|
if (sock->state == SOCKET_STATE_NEW) {
|
||||||
|
*errcode = MP_ENOTCONN;
|
||||||
|
return MP_STREAM_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
// If the peer closed the connection then the lwIP socket API will only return "0" once
|
// If the peer closed the connection then the lwIP socket API will only return "0" once
|
||||||
// from lwip_recvfrom and then block on subsequent calls. To emulate POSIX behaviour,
|
// from lwip_recvfrom and then block on subsequent calls. To emulate POSIX behaviour,
|
||||||
// which continues to return "0" for each call on a closed socket, we set a flag when
|
// which continues to return "0" for each call on a closed socket, we set a flag when
|
||||||
// the peer closed the socket.
|
// the peer closed the socket.
|
||||||
if (sock->peer_closed) {
|
if (sock->state == SOCKET_STATE_PEER_CLOSED) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,7 +516,7 @@ STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size,
|
|||||||
MP_THREAD_GIL_ENTER();
|
MP_THREAD_GIL_ENTER();
|
||||||
}
|
}
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
sock->peer_closed = true;
|
sock->state = SOCKET_STATE_PEER_CLOSED;
|
||||||
}
|
}
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
return r;
|
return r;
|
||||||
@@ -702,6 +718,12 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt
|
|||||||
if (FD_ISSET(socket->fd, &efds)) {
|
if (FD_ISSET(socket->fd, &efds)) {
|
||||||
ret |= MP_STREAM_POLL_HUP;
|
ret |= MP_STREAM_POLL_HUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New (unconnected) sockets are writable and have HUP set.
|
||||||
|
if (socket->state == SOCKET_STATE_NEW) {
|
||||||
|
ret |= (arg & MP_STREAM_POLL_WR) | MP_STREAM_POLL_HUP;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
} else if (request == MP_STREAM_CLOSE) {
|
} else if (request == MP_STREAM_CLOSE) {
|
||||||
if (socket->fd >= 0) {
|
if (socket->fd >= 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user