pycom / pycom-micropython-sigfox

A fork of MicroPython with the ESP32 port customized to run on Pycom's IoT multi-network modules.
MIT License
196 stars 167 forks source link

Deadlock when using multiple SSL Sockets with settimeout #526

Open ltsbkuster opened 3 years ago

ltsbkuster commented 3 years ago

My System, Tested on GPY, Fipy 1.0 and Fipy 1.2

(sysname='GPy', nodename='GPy', release='1.20.2.r4', version='v1.11-ffb0e1c on 2021-01-12', machine='GPy with ESP32', pybytes='1.6.1')

(sysname='FiPy', nodename='FiPy', release='1.20.2.r4', version='v1.11-ffb0e1c on 2021-01-12', machine='FiPy with ESP32', lorawan='1.0.2', sigfox='1.0.1', pybytes='1.6.1')

I start two threads, both are immediatly connecting to the same (or different) SSL Endpoint. If i set a timeout socket.settimeout(5) both threads seem to get stuck at .connect() forever (> 5 seconds). If i remove the timeout, the sockets work, as expected. However if the Endpoint is down i don't run into a timeout, which is what i actually need. If I switch the lines .connect and .wrap_ssl, the deadlock just happens a loop or two later. If i dont use .wrap_ssl and connect to a unencrypted endpoint, it behaves like expected.

import socket
import ussl
import sys

def connect(host, port, message, timeout=None):

    while True:
        sock = None
        ssl_socket = None

        try:

            addr = socket.getaddrinfo(host, port)
            sock = socket.socket()

            if timeout is not None:
                sock.settimeout(timeout)

            ssl_sock = None        

            print("{} wrapping ssl socket".format(message))
            ssl_sock = ussl.wrap_socket(sock)

            print("{} connecting socket".format(message))
            sock.connect(addr[0][4])

            print ("{} successfully connected".format(message))

        except Exception as e:
            sys.print_exception(e)
        finally:

            if ssl_sock is not None:
                ssl_sock.close()

            if sock is not None:
                sock.close()

# not ok  
_thread.start_new_thread(connect, ('www.google.ch', 443, 'thread1', 5))
_thread.start_new_thread(connect, ('www.google.ch', 443, 'thread2', 5))

# OK (no timeout will be set)
# _thread.start_new_thread(connect, ('www.google.ch', 443, 'thread1'))
# _thread.start_new_thread(connect, ('www.google.ch', 443, 'thread2'))

Output if Timeout is set:

thread1 wrapping ssl socket
thread2 wrapping ssl socket
thread1 connecting socket                             # <== First connection is fine
thread2 connecting socket                             # <== thread2 can also connect first time
thread1 successfully connected
thread1 wrapping ssl socket
thread1 connecting socket                              # <== Thread 1 starts to connect
thread2 successfully connected
thread2 wrapping ssl socket
thread2 connecting socket                              # <== Thread 2 starts to connect, after this nothing happens anymore

Thank you for having a look at it. Regards, Beda