extmod/modlwip: Protect socket.accept with lwIP concurrency lock.
This is needed now that the accept queue can have pending connections removed asynchronously.
This commit is contained in:
parent
2ec7838967
commit
490e0f39d1
|
@ -859,15 +859,28 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen);
|
|||
STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
|
||||
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
if (socket->pcb.tcp == NULL) {
|
||||
mp_raise_OSError(MP_EBADF);
|
||||
}
|
||||
if (socket->type != MOD_NETWORK_SOCK_STREAM) {
|
||||
mp_raise_OSError(MP_EOPNOTSUPP);
|
||||
}
|
||||
|
||||
// Create new socket object, do it here because we must not raise an out-of-memory
|
||||
// exception when the LWIP concurrency lock is held
|
||||
lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t);
|
||||
socket2->base.type = &lwip_socket_type;
|
||||
|
||||
MICROPY_PY_LWIP_ENTER
|
||||
|
||||
if (socket->pcb.tcp == NULL) {
|
||||
MICROPY_PY_LWIP_EXIT
|
||||
m_del_obj(lwip_socket_obj_t, socket2);
|
||||
mp_raise_OSError(MP_EBADF);
|
||||
}
|
||||
|
||||
// I need to do this because "tcp_accepted", later, is a macro.
|
||||
struct tcp_pcb *listener = socket->pcb.tcp;
|
||||
if (listener->state != LISTEN) {
|
||||
MICROPY_PY_LWIP_EXIT
|
||||
m_del_obj(lwip_socket_obj_t, socket2);
|
||||
mp_raise_OSError(MP_EINVAL);
|
||||
}
|
||||
|
||||
|
@ -875,26 +888,29 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
|
|||
struct tcp_pcb *volatile *incoming_connection = &lwip_socket_incoming_array(socket)[socket->incoming.connection.iget];
|
||||
if (*incoming_connection == NULL) {
|
||||
if (socket->timeout == 0) {
|
||||
MICROPY_PY_LWIP_EXIT
|
||||
m_del_obj(lwip_socket_obj_t, socket2);
|
||||
mp_raise_OSError(MP_EAGAIN);
|
||||
} else if (socket->timeout != -1) {
|
||||
for (mp_uint_t retries = socket->timeout / 100; retries--;) {
|
||||
mp_uint_t retries = socket->timeout / 100;
|
||||
while (*incoming_connection == NULL) {
|
||||
MICROPY_PY_LWIP_EXIT
|
||||
if (retries-- == 0) {
|
||||
m_del_obj(lwip_socket_obj_t, socket2);
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
}
|
||||
mp_hal_delay_ms(100);
|
||||
if (*incoming_connection != NULL) break;
|
||||
}
|
||||
if (*incoming_connection == NULL) {
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
MICROPY_PY_LWIP_REENTER
|
||||
}
|
||||
} else {
|
||||
while (*incoming_connection == NULL) {
|
||||
MICROPY_PY_LWIP_EXIT
|
||||
poll_sockets();
|
||||
MICROPY_PY_LWIP_REENTER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create new socket object
|
||||
lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t);
|
||||
socket2->base.type = &lwip_socket_type;
|
||||
|
||||
// We get a new pcb handle...
|
||||
socket2->pcb.tcp = *incoming_connection;
|
||||
if (++socket->incoming.connection.iget >= socket->incoming.connection.alloc) {
|
||||
|
@ -916,6 +932,8 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
|
|||
|
||||
tcp_accepted(listener);
|
||||
|
||||
MICROPY_PY_LWIP_EXIT
|
||||
|
||||
// make the return value
|
||||
uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
|
||||
memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip));
|
||||
|
|
Loading…
Reference in New Issue