From 15c620dcc21909daab35c9873a16822e6dcb3d02 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 7 Feb 2017 13:00:24 +0100 Subject: [PATCH] SSL socket blocking error handling --- src/class_receiveDataThread.py | 24 ++++++++++++++++-------- src/class_sendDataThread.py | 20 ++++++++++++++++++-- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index efa0092a..9ed0a311 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -86,11 +86,11 @@ class receiveDataThread(threading.Thread): while state.shutdown == 0: dataLen = len(self.data) try: - ssl = False + isSSL = False if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and self.connectionIsOrWasFullyEstablished and protocol.haveSSL(not self.initiatedConnection)): - ssl = True + isSSL = True dataRecv = self.sslSock.recv(throttle.ReceiveThrottle().chunkSize) else: dataRecv = self.sock.recv(throttle.ReceiveThrottle().chunkSize) @@ -99,13 +99,21 @@ class receiveDataThread(threading.Thread): except socket.timeout: logger.error ('Timeout occurred waiting for data from ' + str(self.peer) + '. Closing receiveData thread. (ID: ' + str(id(self)) + ')') break + except ssl.SSLError as err: + if err.errno == ssl.SSL_ERROR_WANT_READ: + select.select([self.sslSock], [], [], 10) + logger.debug('sock.recv retriable SSL error') + continue + logger.error ('SSL error: %i/%s', err.errno, str(err)) + break except socket.error as err: - if err.errno == errno.EWOULDBLOCK: - if ssl: - select.select([self.sslSock], [], [], 10) - else: - select.select([self.sock], [], [], 10) - logger.error('sock.recv retriable error') + if err.errno in (errno.EAGAIN, errno.EWOULDBLOCK): + select.select([self.sslSock if isSSL else self.sock], [], [], 10) + logger.debug('sock.recv retriable error') + continue + if sys.platform.startswith('win') and err.errno in (errno.WSAEAGAIN, errno.WSAEWOULDBLOCK): + select.select([self.sslSock if isSSL else self.sock], [], [], 10) + logger.debug('sock.recv retriable error') continue logger.error('sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID: ' + str(id(self)) + ').' + str(err.errno) + "/" + str(err)) if self.initiatedConnection and not self.connectionIsOrWasFullyEstablished: diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 64b29530..e403de61 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -5,8 +5,10 @@ import Queue from struct import unpack, pack import hashlib import random -import sys +import select import socket +from ssl import SSLError, SSL_ERROR_WANT_WRITE +import sys from helper_generic import addDataPadding from class_objectHashHolder import * @@ -78,17 +80,31 @@ class sendDataThread(threading.Thread): return while self.buffer and state.shutdown == 0: + isSSL = False try: if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and self.connectionIsOrWasFullyEstablished and protocol.haveSSL(not self.initiatedConnection)): + isSSL = True amountSent = self.sslSock.send(self.buffer[:throttle.SendThrottle().chunkSize]) else: amountSent = self.sock.send(self.buffer[:throttle.SendThrottle().chunkSize]) except socket.timeout: continue + except SSLError as e: + if e.errno == SSL_ERROR_WANT_WRITE: + select.select([], [self.sslSock], [], 10) + logger.debug('sock.recv retriable SSL error') + continue + raise except socket.error as e: - if e.errno == errno.EAGAIN: + if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK): + select.select([], [self.sslSock if isSSL else self.sock], [], 10) + logger.debug('sock.recv retriable error') + continue + if sys.platform.startswith('win') and e.errno in (errno.WSAEAGAIN, errno.WSAEWOULDBLOCK): + select.select([], [self.sslSock if isSSL else self.sock], [], 10) + logger.debug('sock.recv retriable error') continue raise throttle.SendThrottle().wait(amountSent)