Initial port of 3709d2e02bf67ccc272e1f2311e5db125a922ba0 from 'ssh'

Re #17
This commit is contained in:
Jeff Forcier 2012-09-13 17:17:34 -07:00
parent edddc61fb5
commit 8f9b37add4
1 changed files with 95 additions and 83 deletions

View File

@ -1505,6 +1505,10 @@ class Transport (threading.Thread):
# indefinitely, creating a GC cycle and not letting Transport ever be # indefinitely, creating a GC cycle and not letting Transport ever be
# GC'd. it's a bug in Thread.) # GC'd. it's a bug in Thread.)
# Hold reference to 'sys' so we can test sys.modules to detect
# interpreter shutdown.
self.sys = sys
# active=True occurs before the thread is launched, to avoid a race # active=True occurs before the thread is launched, to avoid a race
_active_threads.append(self) _active_threads.append(self)
if self.server_mode: if self.server_mode:
@ -1512,94 +1516,102 @@ class Transport (threading.Thread):
else: else:
self._log(DEBUG, 'starting thread (client mode): %s' % hex(long(id(self)) & 0xffffffffL)) self._log(DEBUG, 'starting thread (client mode): %s' % hex(long(id(self)) & 0xffffffffL))
try: try:
self.packetizer.write_all(self.local_version + '\r\n') try:
self._check_banner() self.packetizer.write_all(self.local_version + '\r\n')
self._send_kex_init() self._check_banner()
self._expect_packet(MSG_KEXINIT) self._send_kex_init()
self._expect_packet(MSG_KEXINIT)
while self.active: while self.active:
if self.packetizer.need_rekey() and not self.in_kex: if self.packetizer.need_rekey() and not self.in_kex:
self._send_kex_init() self._send_kex_init()
try: try:
ptype, m = self.packetizer.read_message() ptype, m = self.packetizer.read_message()
except NeedRekeyException: except NeedRekeyException:
continue
if ptype == MSG_IGNORE:
continue
elif ptype == MSG_DISCONNECT:
self._parse_disconnect(m)
self.active = False
self.packetizer.close()
break
elif ptype == MSG_DEBUG:
self._parse_debug(m)
continue
if len(self._expected_packet) > 0:
if ptype not in self._expected_packet:
raise SSHException('Expecting packet from %r, got %d' % (self._expected_packet, ptype))
self._expected_packet = tuple()
if (ptype >= 30) and (ptype <= 39):
self.kex_engine.parse_next(ptype, m)
continue continue
if ptype == MSG_IGNORE:
if ptype in self._handler_table: continue
self._handler_table[ptype](self, m) elif ptype == MSG_DISCONNECT:
elif ptype in self._channel_handler_table: self._parse_disconnect(m)
chanid = m.get_int()
chan = self._channels.get(chanid)
if chan is not None:
self._channel_handler_table[ptype](chan, m)
elif chanid in self.channels_seen:
self._log(DEBUG, 'Ignoring message for dead channel %d' % chanid)
else:
self._log(ERROR, 'Channel request for unknown channel %d' % chanid)
self.active = False self.active = False
self.packetizer.close() self.packetizer.close()
elif (self.auth_handler is not None) and (ptype in self.auth_handler._handler_table): break
self.auth_handler._handler_table[ptype](self.auth_handler, m) elif ptype == MSG_DEBUG:
self._parse_debug(m)
continue
if len(self._expected_packet) > 0:
if ptype not in self._expected_packet:
raise SSHException('Expecting packet from %r, got %d' % (self._expected_packet, ptype))
self._expected_packet = tuple()
if (ptype >= 30) and (ptype <= 39):
self.kex_engine.parse_next(ptype, m)
continue
if ptype in self._handler_table:
self._handler_table[ptype](self, m)
elif ptype in self._channel_handler_table:
chanid = m.get_int()
chan = self._channels.get(chanid)
if chan is not None:
self._channel_handler_table[ptype](chan, m)
elif chanid in self.channels_seen:
self._log(DEBUG, 'Ignoring message for dead channel %d' % chanid)
else:
self._log(ERROR, 'Channel request for unknown channel %d' % chanid)
self.active = False
self.packetizer.close()
elif (self.auth_handler is not None) and (ptype in self.auth_handler._handler_table):
self.auth_handler._handler_table[ptype](self.auth_handler, m)
else:
self._log(WARNING, 'Oops, unhandled type %d' % ptype)
msg = Message()
msg.add_byte(chr(MSG_UNIMPLEMENTED))
msg.add_int(m.seqno)
self._send_message(msg)
except SSHException, e:
self._log(ERROR, 'Exception: ' + str(e))
self._log(ERROR, util.tb_strings())
self.saved_exception = e
except EOFError, e:
self._log(DEBUG, 'EOF in transport thread')
#self._log(DEBUG, util.tb_strings())
self.saved_exception = e
except socket.error, e:
if type(e.args) is tuple:
emsg = '%s (%d)' % (e.args[1], e.args[0])
else: else:
self._log(WARNING, 'Oops, unhandled type %d' % ptype) emsg = e.args
msg = Message() self._log(ERROR, 'Socket exception: ' + emsg)
msg.add_byte(chr(MSG_UNIMPLEMENTED)) self.saved_exception = e
msg.add_int(m.seqno) except Exception, e:
self._send_message(msg) self._log(ERROR, 'Unknown exception: ' + str(e))
except SSHException, e: self._log(ERROR, util.tb_strings())
self._log(ERROR, 'Exception: ' + str(e)) self.saved_exception = e
self._log(ERROR, util.tb_strings()) _active_threads.remove(self)
self.saved_exception = e for chan in self._channels.values():
except EOFError, e: chan._unlink()
self._log(DEBUG, 'EOF in transport thread') if self.active:
#self._log(DEBUG, util.tb_strings()) self.active = False
self.saved_exception = e self.packetizer.close()
except socket.error, e: if self.completion_event != None:
if type(e.args) is tuple: self.completion_event.set()
emsg = '%s (%d)' % (e.args[1], e.args[0]) if self.auth_handler is not None:
else: self.auth_handler.abort()
emsg = e.args for event in self.channel_events.values():
self._log(ERROR, 'Socket exception: ' + emsg) event.set()
self.saved_exception = e try:
except Exception, e: self.lock.acquire()
self._log(ERROR, 'Unknown exception: ' + str(e)) self.server_accept_cv.notify()
self._log(ERROR, util.tb_strings()) finally:
self.saved_exception = e self.lock.release()
_active_threads.remove(self) self.sock.close()
for chan in self._channels.values(): except:
chan._unlink() # Don't raise spurious 'NoneType has no attribute X' errors when we
if self.active: # wake up during interpreter shutdown. Or rather -- raise
self.active = False # everything *if* sys.modules (used as a convenient sentinel)
self.packetizer.close() # appears to still exist.
if self.completion_event != None: if self.sys.modules is not None:
self.completion_event.set() raise
if self.auth_handler is not None:
self.auth_handler.abort()
for event in self.channel_events.values():
event.set()
try:
self.lock.acquire()
self.server_accept_cv.notify()
finally:
self.lock.release()
self.sock.close()
### protocol stages ### protocol stages