fixed handling of SSL errors

This commit is contained in:
tomk 2008-08-09 12:16:42 +00:00
parent cbfa9d97df
commit 4504861084
7 changed files with 50 additions and 46 deletions

View File

@ -515,13 +515,12 @@ class Connection(ConnectionHandlers):
'connection_types').split() 'connection_types').split()
else: else:
self._connection_types = ['tls', 'ssl', 'plain'] self._connection_types = ['tls', 'ssl', 'plain']
#THEHACK
#self._connection_types = ['ssl', 'plain']
if self._proxy and self._proxy['type']=='bosh': if self._proxy and self._proxy['type']=='bosh':
# with BOSH, we can't do TLS negotiation with <starttls>, we do only "plain" # with BOSH, we can't do TLS negotiation with <starttls>, we do only "plain"
# connection and TLS with handshake right after TCP connecting ("ssl") # connection and TLS with handshake right after TCP connecting ("ssl")
try: self._connection_types.remove('tls') try:
self._connection_types.remove('tls')
except ValueError: pass except ValueError: pass
host = self.select_next_host(self._hosts) host = self.select_next_host(self._hosts)
@ -553,7 +552,12 @@ class Connection(ConnectionHandlers):
if self._current_type == 'ssl': if self._current_type == 'ssl':
# SSL (force TLS on different port than plain) # SSL (force TLS on different port than plain)
port = self._current_host['ssl_port'] # If we do TLS over BOSH, port of XMPP server should be the standard one
# and TLS should be negotiated because immediate TLS on 5223 is deprecated
if self._proxy and self._proxy['type']=='bosh':
port = self._current_host['port']
else:
port = self._current_host['ssl_port']
elif self._current_type == 'tls': elif self._current_type == 'tls':
# TLS - negotiate tls after XMPP stream is estabilished # TLS - negotiate tls after XMPP stream is estabilished
port = self._current_host['port'] port = self._current_host['port']

View File

@ -113,9 +113,8 @@ class NonBlockingBOSH(NonBlockingTransport):
self.disconnect() self.disconnect()
return return
print 'SSSSSSSSSSEEEEEEEEEND' #Hack for making the non-secure warning dialog work
if hasattr(self._owner, 'NonBlockingNonSASL') or hasattr(self._owner, 'SASL'): if hasattr(self._owner, 'NonBlockingNonSASL') or hasattr(self._owner, 'SASL'):
#FIXME: Hack for making the non-secure warning dialog work
self.send_BOSH(None) self.send_BOSH(None)
else: else:
self.http_socks[0]._plug_idle(writable=False, readable=True) self.http_socks[0]._plug_idle(writable=False, readable=True)
@ -453,31 +452,31 @@ class AckChecker():
class KeyStack(): class KeyStack():
def __init__(self, count): def __init__(self, count):
self.count = count self.count = count
self.keys = [] self.keys = []
self.reset() self.reset()
self.first_call = True self.first_call = True
def reset(self): def reset(self):
seed = str(get_rand_number()) seed = str(get_rand_number())
self.keys = [sha.new(seed).hexdigest()] self.keys = [sha.new(seed).hexdigest()]
for i in range(self.count-1): for i in range(self.count-1):
curr_seed = self.keys[i] curr_seed = self.keys[i]
self.keys.append(sha.new(curr_seed).hexdigest()) self.keys.append(sha.new(curr_seed).hexdigest())
def get(self): def get(self):
if self.first_call: if self.first_call:
self.first_call = False self.first_call = False
return (None, self.keys.pop()) return (None, self.keys.pop())
if len(self.keys)>1: if len(self.keys)>1:
return (self.keys.pop(), None) return (self.keys.pop(), None)
else: else:
last_key = self.keys.pop() last_key = self.keys.pop()
self.reset() self.reset()
new_key = self.keys.pop() new_key = self.keys.pop()
return (last_key, new_key) return (last_key, new_key)
# http://www.xmpp.org/extensions/xep-0124.html#errorstatus-terminal # http://www.xmpp.org/extensions/xep-0124.html#errorstatus-terminal
bosh_errors = { bosh_errors = {

View File

@ -23,7 +23,7 @@ These classes can be used for simple applications "AS IS" though.
import socket import socket
import transports_nb, tls_nb, dispatcher_nb, auth_nb, roster_nb, protocol, bosh import transports_nb, dispatcher_nb, auth_nb, roster_nb, protocol, bosh
from client import * from client import *
from protocol import NS_TLS from protocol import NS_TLS
@ -234,6 +234,7 @@ class NBCommonClient:
xmlns=NS_TLS) xmlns=NS_TLS)
self.send('<starttls xmlns="%s"/>' % NS_TLS) self.send('<starttls xmlns="%s"/>' % NS_TLS)
else: else:
# we got <proceed> or <failure>
if tag.getNamespace() <> NS_TLS: if tag.getNamespace() <> NS_TLS:
self._on_connect_failure('Unknown namespace: %s' % tag.getNamespace()) self._on_connect_failure('Unknown namespace: %s' % tag.getNamespace())
return return

View File

@ -110,9 +110,8 @@ class IdleQueue:
if alarm_time > current_time: if alarm_time > current_time:
break break
if self.alarms.has_key(alarm_time): if self.alarms.has_key(alarm_time):
for cb in self.alarms[alarm_time]: for cb in self.alarms[alarm_time]: cb()
cb() if self.alarms.has_key(alarm_time): del(self.alarms[alarm_time])
del(self.alarms[alarm_time])
def plug_idle(self, obj, writable = True, readable = True): def plug_idle(self, obj, writable = True, readable = True):
if obj.fd == -1: if obj.fd == -1:

View File

@ -20,7 +20,6 @@ I'm personally using it in many other separate projects. It is designed to be as
import xml.parsers.expat import xml.parsers.expat
import logging import logging
log = logging.getLogger('gajim.c.x.simplexml') log = logging.getLogger('gajim.c.x.simplexml')
#log.setLevel(logging.DEBUG)
def XMLescape(txt): def XMLescape(txt):
'''Returns provided string with symbols & < > " replaced by their respective XML entities.''' '''Returns provided string with symbols & < > " replaced by their respective XML entities.'''

View File

@ -150,7 +150,6 @@ class PyOpenSSLWrapper(SSLWrapper):
else: retval = self.sslobj.recv(bufsize, flags) else: retval = self.sslobj.recv(bufsize, flags)
except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError), e: except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError), e:
log.debug("Recv: Want-error: " + repr(e)) log.debug("Recv: Want-error: " + repr(e))
pass
except OpenSSL.SSL.SysCallError, e: except OpenSSL.SSL.SysCallError, e:
log.debug("Recv: Got OpenSSL.SSL.SysCallError: " + repr(e), exc_info=True) log.debug("Recv: Got OpenSSL.SSL.SysCallError: " + repr(e), exc_info=True)
#traceback.print_exc() #traceback.print_exc()
@ -202,8 +201,7 @@ class StdlibSSLWrapper(SSLWrapper):
try: try:
return self.sslobj.read(bufsize) return self.sslobj.read(bufsize)
except socket.sslerror, e: except socket.sslerror, e:
#log.debug("Recv: Caught socket.sslerror:", exc_info=True) log.debug("Recv: Caught socket.sslerror:", exc_info=True)
#traceback.print_exc()
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 SSLWrapper.Error(self.sock or self.sslobj, e) raise SSLWrapper.Error(self.sock or self.sslobj, e)
return None return None
@ -213,8 +211,7 @@ class StdlibSSLWrapper(SSLWrapper):
try: try:
return self.sslobj.write(data) return self.sslobj.write(data)
except socket.sslerror, e: except socket.sslerror, e:
#log.debug("Send: Caught socket.sslerror:", exc_info=True) log.debug("Send: Caught socket.sslerror:", exc_info=True)
#traceback.print_exc()
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 SSLWrapper.Error(self.sock or self.sslobj, e) raise SSLWrapper.Error(self.sock or self.sslobj, e)
return 0 return 0
@ -274,13 +271,12 @@ class NonBlockingTLS(PlugIn):
print >> stream, "PKey type: %s (%d)" % (typedict.get(pkey.type(), "Unknown"), pkey.type()) print >> stream, "PKey type: %s (%d)" % (typedict.get(pkey.type(), "Unknown"), pkey.type())
def _startSSL(self): def _startSSL(self):
''' Immidiatedly switch socket to TLS mode. Used internally.''' ''' Immediatedly switch socket to TLS mode. Used internally.'''
log.debug("_startSSL called") log.debug("_startSSL called")
if USE_PYOPENSSL: return self._startSSL_pyOpenSSL() if USE_PYOPENSSL: return self._startSSL_pyOpenSSL()
else: return self._startSSL_stdlib() else: return self._startSSL_stdlib()
def _startSSL_pyOpenSSL(self): def _startSSL_pyOpenSSL(self):
#log.debug("_startSSL_pyOpenSSL called, thread id: %s", str(thread.get_ident()))
log.debug("_startSSL_pyOpenSSL called") log.debug("_startSSL_pyOpenSSL called")
tcpsock = self._owner tcpsock = self._owner
# FIXME: should method be configurable? # FIXME: should method be configurable?

View File

@ -21,7 +21,7 @@ from simplexml import ustr
from client import PlugIn from client import PlugIn
from idlequeue import IdleObject from idlequeue import IdleObject
from protocol import * from protocol import *
from tls_nb import NonBlockingTLS import tls_nb
import sys import sys
import os import os
@ -304,7 +304,7 @@ class NonBlockingTCP(NonBlockingTransport, IdleObject):
def tls_init(self, on_succ, on_fail): def tls_init(self, on_succ, on_fail):
cacerts, mycerts = self.certs cacerts, mycerts = self.certs
result = NonBlockingTLS(cacerts, mycerts).PlugIn(self) result = tls_nb.NonBlockingTLS(cacerts, mycerts).PlugIn(self)
if result: on_succ() if result: on_succ()
else: on_fail() else: on_fail()
@ -436,7 +436,10 @@ class NonBlockingTCP(NonBlockingTransport, IdleObject):
def _do_receive(self): def _do_receive(self):
''' Reads all pending incoming data. Calls owner's disconnected() method if appropriate.''' ''' Reads all pending incoming data. Calls owner's disconnected() method if appropriate.'''
ERR_DISCONN = -2 # Misc error signifying that we got disconnected # Misc error signifying that we got disconnected
ERR_DISCONN = -2
# code for unknown/other errors
ERR_OTHER = -3
received = None received = None
errnum = 0 errnum = 0
errstr = 'No Error Set' errstr = 'No Error Set'
@ -444,9 +447,13 @@ class NonBlockingTCP(NonBlockingTransport, IdleObject):
try: try:
# get as many bites, as possible, but not more than RECV_BUFSIZE # get as many bites, as possible, but not more than RECV_BUFSIZE
received = self._recv(RECV_BUFSIZE) received = self._recv(RECV_BUFSIZE)
except (socket.error, socket.herror, socket.gaierror), (errnum, errstr): except socket.error, (errnum, errstr):
# save exception number and message to errnum, errstr # save exception number and message to errnum, errstr
log.info("_do_receive: got %s:" % received , exc_info=True) log.info("_do_receive: got %s:" % received , exc_info=True)
except tls_nb.SSLWrapper.Error, e:
log.info("_do_receive, caugth SSL error: got %s:" % received , exc_info=True)
errnum = tls_nb.gattr(e, 'errno') or ERR_OTHER
errstr = tls_nb.gattr(e, 'exc_str')
if received == '': if received == '':
errnum = ERR_DISCONN errnum = ERR_DISCONN
@ -456,25 +463,24 @@ class NonBlockingTCP(NonBlockingTransport, IdleObject):
# ECONNRESET - connection you are trying to access has been reset by the peer # ECONNRESET - connection you are trying to access has been reset by the peer
# ENOTCONN - Transport endpoint is not connected # ENOTCONN - Transport endpoint is not connected
# ESHUTDOWN - shutdown(2) has been called on a socket to close down the # ESHUTDOWN - shutdown(2) has been called on a socket to close down the
# sending end of the transmision, and then data was attempted to be sent # sending end of the transmision, and then data was attempted to be sent
log.error("Connection to %s lost: %s %s" % ( self.server, errnum, errstr), exc_info=True) log.error("Connection to %s lost: %s %s" % ( self.server, errnum, errstr), exc_info=True)
if hasattr(self, 'on_remote_disconnect'): self.on_remote_disconnect() if hasattr(self, 'on_remote_disconnect'): self.on_remote_disconnect()
else: self.disconnect() else: self.disconnect()
return return
if received is None: if received is None:
# in case of SSL error - because there are two types of TLS wrappers, the TLS # because there are two types of TLS wrappers, the TLS plugin recv method
# pluging recv method returns None in case of error # returns None in case of error
print 'SSL ERROR'
if errnum != 0: if errnum != 0:
log.error("CConnection to %s lost: %s %s" % (self.server, errnum, errstr)) log.error("CConnection to %s lost: %s %s" % (self.server, errnum, errstr))
self.disconnect() self.disconnect()
return return
received = '' received = ''
return
# we have received some bytes, stop the timeout! # we have received some bytes, stop the timeout!
self.renew_send_timeout() self.renew_send_timeout()
print '-->%s<--' % received
# pass received data to owner # pass received data to owner
if self.on_receive: if self.on_receive:
self.raise_event(DATA_RECEIVED, received) self.raise_event(DATA_RECEIVED, received)
@ -732,7 +738,7 @@ class NBHTTPProxySocket(NBProxySocket):
return return
if len(reply) != 2: if len(reply) != 2:
pass pass
NonBlockingT._on_connect(self) NonBlockingTCP._on_connect(self)
#self.onreceive(self._on_proxy_auth) #self.onreceive(self._on_proxy_auth)
def _on_proxy_auth(self, reply): def _on_proxy_auth(self, reply):