- Typo
[pyopenssl]
- Better exception handling
- Prevent 100% cpu usage when ssl handshake is slow
This commit is contained in:
junglecow 2006-11-28 01:02:31 +00:00
parent 3c77ffd406
commit 5cb241b8c0
2 changed files with 84 additions and 40 deletions

View File

@ -74,10 +74,8 @@ class NBCommonClient(CommonClient):
''' Called on disconnection. Calls disconnect handlers and cleans things up. ''' ''' Called on disconnection. Calls disconnect handlers and cleans things up. '''
self.connected='' self.connected=''
self.DEBUG(self.DBG,'Disconnect detected','stop') self.DEBUG(self.DBG,'Disconnect detected','stop')
self.disconnect_handlers.reverse() for i in reversed(self.disconnect_handlers):
for i in self.disconnect_handlers:
i() i()
self.disconnect_handlers.reverse()
if self.__dict__.has_key('NonBlockingRoster'): if self.__dict__.has_key('NonBlockingRoster'):
self.NonBlockingRoster.PlugOut() self.NonBlockingRoster.PlugOut()
if self.__dict__.has_key('NonBlockingBind'): if self.__dict__.has_key('NonBlockingBind'):

View File

@ -24,6 +24,7 @@ from transports import *
import sys import sys
import os import os
import errno import errno
import time
import traceback import traceback
import thread import thread
@ -67,14 +68,55 @@ def torf(cond, tv, fv):
if cond: return tv if cond: return tv
return fv return fv
class SSLWrapper: def gattr(obj, attr, default=None):
def Error(Exception): try:
parent = Exception return getattr(obj, attr)
def __init__(this, *args): except:
this.parent.__init__(this, *args) return default
def __init__(this, sslobj): class SSLWrapper:
class Error(IOError):
def __init__(this, sock=None, exc=None, errno=None, strerror=None, peer=None):
this.parent = IOError
this.exc = exc
this.errno = errno or gattr(this.exc, 'errno', 0)
this.strerror = strerror or gattr(this.exc, 'strerror') or gattr(this.exc, 'args')
this.parent.__init__(this, errno, strerror)
this.peer = peer
this.exc_name = None
if this.exc is not None:
this.exc_name = str(this.exc.__class__)
this.exc_args = gattr(this.exc, 'args')
this.exc_str = str(this.exc)
this.exc_repr = repr(this.exc)
if this.peer is None and sock is not None:
try:
ppeer = this.obj.getpeername()
if len(ppeer) == 2 and isinstance(ppeer[0], basestring) \
and isinstance(ppeer[1], int):
this.peer = ppeer
except: pass
def __str__(this):
s = str(this.__class__)
if this.peer: s += "for %s:%d" % this.peer
if this.errno is not None: s += ": [Errno: %d]" % this.errno
if this.strerror: s += " (%s)" % this.strerror
if this.exc_name:
s += ", Caused by %s" % this.exc_name
if this.exc_str:
if this.strerror: s += "(%s)" % this.exc_str
else: s += "(%s)" % this.exc_args
return s
def __init__(this, sslobj, sock=None):
this.sslobj = sslobj this.sslobj = sslobj
this.sock = sock
print "init called with", sslobj print "init called with", sslobj
# We can return None out of this function to signal that no data is # We can return None out of this function to signal that no data is
@ -91,9 +133,9 @@ class SSLWrapper:
class PyOpenSSLWrapper(SSLWrapper): class PyOpenSSLWrapper(SSLWrapper):
'''Wrapper class for PyOpenSSL's recv() and send() methods''' '''Wrapper class for PyOpenSSL's recv() and send() methods'''
parent = SSLWrapper
def __init__(this, *args): def __init__(this, *args):
this.parent = SSLWrapper
this.parent.__init__(this, *args) this.parent.__init__(this, *args)
def is_numtoolarge(this, e): def is_numtoolarge(this, e):
@ -111,20 +153,19 @@ class PyOpenSSLWrapper(SSLWrapper):
except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError), e: except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError), e:
log.debug("Recv: " + repr(e)) log.debug("Recv: " + repr(e))
except OpenSSL.SSL.SysCallError, e: except OpenSSL.SSL.SysCallError, e:
log.error("Got OpenSSL.SSL.SysCallError: " + repr(e)) log.error("Recv: Got OpenSSL.SSL.SysCallError: " + repr(e))
traceback.print_exc() traceback.print_exc()
raise SSLWrapper.Error(('OpenSSL.SSL.SysCallError', e.args)) raise SSLWrapper.Error(this.sock or this.sslobj, e)
except OpenSSL.SSL.Error, e: except OpenSSL.SSL.Error, e:
"Recv: Caught OpenSSL.SSL.Error:" if this.is_numtoolarge(e):
# warn, but ignore this exception
log.warning("Recv: OpenSSL: asn1enc: first num too large (ignored)")
else:
log.warning("Recv: Caught OpenSSL.SSL.Error:")
traceback.print_exc() traceback.print_exc()
print "Current Stack:" print "Current Stack:"
traceback.print_stack() traceback.print_stack()
if this.is_numtoolarge(e): raise SSLWrapper.Error(this.sock or this.sslobj, e)
# print an error but ignore this exception
log.warning("Recv: OpenSSL: asn1enc: first num too large (eaten)")
else:
raise
return retval return retval
def send(this, data, flags=None): def send(this, data, flags=None):
@ -134,23 +175,28 @@ class PyOpenSSLWrapper(SSLWrapper):
else: return this.sslobj.send(data, flags) else: return this.sslobj.send(data, flags)
except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError), e: except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError), e:
log.debug("Send: " + repr(e)) log.debug("Send: " + repr(e))
time.sleep(0.1) # prevent 100% CPU usage
except OpenSSL.SSL.SysCallError, e:
log.error("Recv: Got OpenSSL.SSL.SysCallError: " + repr(e))
traceback.print_exc()
raise SSLWrapper.Error(this.sock or this.sslobj, e)
except OpenSSL.SSL.Error, e: except OpenSSL.SSL.Error, e:
print "Send: Caught OpenSSL.SSL.Error:" if this.is_numtoolarge(e):
# warn, but ignore this exception
log.warning("Send: OpenSSL: asn1enc: first num too large (ignored)")
else:
log.warning("Send: Caught OpenSSL.SSL.Error:")
traceback.print_exc() traceback.print_exc()
print "Current Stack:" print "Current Stack:"
traceback.print_stack() traceback.print_stack()
if this.is_numtoolarge(e): raise SSLWrapper.Error(this.sock or this.sslobj, e)
# warn, but ignore this exception
log.warning("Send: OpenSSL: asn1enc: first num too large (ignoring)")
else:
raise
return 0 return 0
class StdlibSSLWrapper(SSLWrapper): class StdlibSSLWrapper(SSLWrapper):
'''Wrapper class for Python's socket.ssl read() and write() methods''' '''Wrapper class for Python's socket.ssl read() and write() methods'''
parent = SSLWrapper
def __init__(this, *args): def __init__(this, *args):
this.parent = SSLWrapper
this.parent.__init__(this, *args) this.parent.__init__(this, *args)
def recv(this, bufsize, flags=None): def recv(this, bufsize, flags=None):
@ -165,7 +211,7 @@ class StdlibSSLWrapper(SSLWrapper):
print "Current Stack:" print "Current Stack:"
traceback.print_stack() traceback.print_stack()
if e.args[0] not in (socket.SSL_ERROR_WANT_READ, socket.SSL_ERROR_WANT_WRITE): if e.args[0] not in (socket.SSL_ERROR_WANT_READ, socket.SSL_ERROR_WANT_WRITE):
raise raise SSLWrapper.Error(this.sock or this.sslobj, e)
return retval return retval
@ -180,7 +226,7 @@ class StdlibSSLWrapper(SSLWrapper):
print "Current Stack:" print "Current Stack:"
traceback.print_stack() traceback.print_stack()
if e.args[0] not in (socket.SSL_ERROR_WANT_READ, socket.SSL_ERROR_WANT_WRITE): if e.args[0] not in (socket.SSL_ERROR_WANT_READ, socket.SSL_ERROR_WANT_WRITE):
raise raise SSLWrapper.Error(this.sock or this.sslobj, e)
return 0 return 0
class NonBlockingTcp(PlugIn, IdleObject): class NonBlockingTcp(PlugIn, IdleObject):
@ -305,12 +351,10 @@ class NonBlockingTcp(PlugIn, IdleObject):
self.remove_timeout() self.remove_timeout()
self._owner.disconnected() self._owner.disconnected()
self.idlequeue.unplug_idle(self.fd) self.idlequeue.unplug_idle(self.fd)
try: try: self._sock.shutdown(socket.SHUT_RDWR)
self._sock.shutdown(socket.SHUT_RDWR) except: traceback.print_exc()
self._sock.close() try: self._sock.close()
except: except: traceback.print_exc()
traceback.print_exc()
# socket is already closed
# socket descriptor cannot be (un)plugged anymore # socket descriptor cannot be (un)plugged anymore
self.fd = -1 self.fd = -1
if self.on_disconnect: if self.on_disconnect:
@ -374,9 +418,11 @@ class NonBlockingTcp(PlugIn, IdleObject):
traceback.print_stack() traceback.print_stack()
errnum = ERR_OTHER errnum = ERR_OTHER
errtxt = repr("socket.sslerror: " + e.args) errtxt = repr("socket.sslerror: " + e.args)
except SSLWrapper.Error: except SSLWrapper.Error, e:
errnum = ERR_OTHER print "caught " + str(e)
errtxt = repr(e.args) errnum = gattr(e, 'errno', ERR_OTHER)
if errnum == 0: errnum = ERR_OTHER # unset, but we must put a status
errtxt = gattr(e, 'strerror') or repr(e.args)
# Should we really do this? In C, recv() will happily return 0 # Should we really do this? In C, recv() will happily return 0
# in nonblocking mode when there is no data waiting, and in # in nonblocking mode when there is no data waiting, and in
@ -400,7 +446,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
self.DEBUG(errtxt, 'error') self.DEBUG(errtxt, 'error')
log.error("Error: " + errtxt) log.error("Error: " + errtxt)
if self.state >= 0: if self.state >= 0:
self.disconnect() self.pollend()
return return
received = '' received = ''
@ -682,7 +728,7 @@ class NonBlockingTLS(PlugIn):
tcpsock._sock.setblocking(False) tcpsock._sock.setblocking(False)
tcpsock._sslIssuer = tcpsock._sslObj.issuer() tcpsock._sslIssuer = tcpsock._sslObj.issuer()
tcpsock._sslServer = tcpsock._sslObj.server() tcpsock._sslServer = tcpsock._sslObj.server()
wrapper = StdlibSSLWrapper(tcpsock._sslObj) wrapper = StdlibSSLWrapper(tcpsock._sslObj, tcpsock._sock)
tcpsock._recv = wrapper.recv tcpsock._recv = wrapper.recv
tcpsock._send = wrapper.send tcpsock._send = wrapper.send
self.starttls='success' self.starttls='success'