extmod/modlwip: Protect socket.accept with lwIP concurrency lock.

This is needed now that the accept queue can have pending connections
removed asynchronously.
pull/4668/head
Damien George 2019-03-27 16:11:33 +11:00
rodzic 2ec7838967
commit 490e0f39d1
1 zmienionych plików z 30 dodań i 12 usunięć

Wyświetl plik

@ -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));