Avoid ResourceWarning if shutdown failed for some reason
The following warning appears transiently from time to time while working with websockets:
/usr/lib/python3/dist-packages/ws4py/websocket.py:230: ResourceWarning: unclosed <ssl.SSLSocket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('10.25.11.39', 40618)>
self.sock = None
ResourceWarning: Enable tracemalloc to get the object allocation traceback
Investigation shows that this warning appears if self.sock.shutdown(socket.SHUT_RDWR) (line 225) throws exception and thus self.sock.close() (line 226) is not called and execution proceeds straight to self.sock = None (line 230), and that produces the ResourceWarning mentioned above.
The exception itself is hidden by pass statement (line 228), but additional investigation showed the following example of that exception:
File "/usr/lib/python3/dist-packages/ws4py/websocket.py", line 225, in close_connection
self.sock.shutdown(socket.SHUT_RDWR)
File "/usr/lib/python3.8/ssl.py", line 1280, in shutdown
super().shutdown(how)
OSError: [Errno 107] Transport endpoint is not connected
The reliable reproduction of this situation is problematic, but I've created the following test that reproduces the problem reliably and should pass if the problem is fixed:
from ws4py.client.threadedclient import WebSocketClient
def received_message(self, m):
self.close()
def opened(self):
self.send('blah\n' * 10000)
def shutdown(self):
raise Exception('shutdown')
def close_connection(self):
self.sock.shutdown = shutdown
original_close_connection(self)
WebSocketClient.received_message = received_message
WebSocketClient.opened = opened
original_close_connection = WebSocketClient.close_connection
WebSocketClient.close_connection = close_connection
ws = WebSocketClient('wss://websocketstest.com/service')
ws.connect()
ws.run_forever()
Here's the output:
$ python3 -W all test.py
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/ws4py/websocket.py", line 225, in close_connection
self.sock.shutdown(socket.SHUT_RDWR)
File "test.py", line 10, in shutdown
raise Exception('shutdown')
Exception: shutdown
/usr/lib/python3/dist-packages/ws4py/websocket.py:231: ResourceWarning: unclosed <ssl.SSLSocket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('192.168.1.4', 50110), raddr=('88.198.55.153', 443)>
self.sock = None
ResourceWarning: Enable tracemalloc to get the object allocation traceback
$ python3
Python 3.8.10 (default, Sep 28 2021, 16:10:42)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ws4py
>>> ws4py.__version__
'0.5.1'
$ uname -a
Linux i-buildcore-01-11 5.4.0-89-generic #100-Ubuntu SMP Fri Sep 24 14:50:10 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/issue
Ubuntu 20.04.3 LTS \n \l
I've provided a test to reproduce the problem.