[project @ Arch-1:robey@lag.net--2003-public%secsh--dev--1.0--patch-60]
limit read/write requests to 32KB, advertise 32KB max packet size one of the unit tests was failing because the openssh sftp server was dropping the connection without any error. turns out they have a maximum allowed write size (possibly around 64KB). the sftp rfcs have a small hint that some servers may drop read/write requests of greater than 32KB. so, all reads are limited to 32KB, and all writes > 32KB are now chopped up and sent in 32KB chunks. this seems to keep openssh happy. also, we now advertise 32KB max packet size instead of 8KB (the speed improves a lot), and log when we read/write a packet. and sftp files are flushed on seek.
This commit is contained in:
parent
f0ba3c482e
commit
146417c56c
|
@ -15,7 +15,7 @@
|
|||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Foobar; if not, write to the Free Software Foundation, Inc.,
|
||||
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
import struct, socket
|
||||
|
@ -121,6 +121,11 @@ class SFTPError (Exception):
|
|||
|
||||
|
||||
class SFTPFile (BufferedFile):
|
||||
|
||||
# some sftp servers will choke if you send read/write requests larger than
|
||||
# this size.
|
||||
MAX_REQUEST_SIZE = 32768
|
||||
|
||||
def __init__(self, sftp, handle, mode='r', bufsize=-1):
|
||||
BufferedFile.__init__(self)
|
||||
self.sftp = sftp
|
||||
|
@ -143,16 +148,23 @@ class SFTPFile (BufferedFile):
|
|||
self.sftp._request(CMD_CLOSE, self.handle)
|
||||
|
||||
def _read(self, size):
|
||||
size = min(size, self.MAX_REQUEST_SIZE)
|
||||
t, msg = self.sftp._request(CMD_READ, self.handle, long(self._realpos), int(size))
|
||||
if t != CMD_DATA:
|
||||
raise SFTPError('Expected data')
|
||||
return msg.get_string()
|
||||
|
||||
def _write(self, data):
|
||||
t, msg = self.sftp._request(CMD_WRITE, self.handle, long(self._realpos), str(data))
|
||||
offset = 0
|
||||
while offset < len(data):
|
||||
chunk = min(len(data) - offset, self.MAX_REQUEST_SIZE)
|
||||
t, msg = self.sftp._request(CMD_WRITE, self.handle, long(self._realpos + offset),
|
||||
str(data[offset : offset + chunk]))
|
||||
offset += chunk
|
||||
return len(data)
|
||||
|
||||
def seek(self, offset, whence=0):
|
||||
self.flush()
|
||||
if whence == self.SEEK_SET:
|
||||
self._realpos = self._pos = offset
|
||||
elif whence == self.SEEK_CUR:
|
||||
|
@ -160,7 +172,7 @@ class SFTPFile (BufferedFile):
|
|||
self._pos += offset
|
||||
else:
|
||||
self._realpos = self._pos = self._get_size() + offset
|
||||
self._rbuffer = self._wbuffer = ''
|
||||
self._rbuffer = ''
|
||||
|
||||
def stat(self):
|
||||
"""
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Foobar; if not, write to the Free Software Foundation, Inc.,
|
||||
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
"""
|
||||
|
@ -162,8 +162,8 @@ class BaseTransport (threading.Thread):
|
|||
self.channel_counter = 1
|
||||
self.logger = logging.getLogger('paramiko.transport')
|
||||
self.window_size = 65536
|
||||
self.max_packet_size = 8192
|
||||
self.ultra_debug = 0
|
||||
self.max_packet_size = 32768
|
||||
self.ultra_debug = False
|
||||
self.saved_exception = None
|
||||
# used for noticing when to re-key:
|
||||
self.received_bytes = 0
|
||||
|
@ -792,7 +792,9 @@ class BaseTransport (threading.Thread):
|
|||
def _send_message(self, data):
|
||||
# FIXME: should we check for rekeying here too?
|
||||
# encrypt this sucka
|
||||
packet = self._build_packet(str(data))
|
||||
data = str(data)
|
||||
self._log(DEBUG, 'Write packet $%x, length %d' % (ord(data[0]), len(data)))
|
||||
packet = self._build_packet(data)
|
||||
if self.ultra_debug:
|
||||
self._log(DEBUG, util.format_binary(packet, 'OUT: '))
|
||||
if self.engine_out != None:
|
||||
|
@ -861,8 +863,10 @@ class BaseTransport (threading.Thread):
|
|||
self.received_packets_overflow += 1
|
||||
if self.received_packets_overflow >= 20:
|
||||
raise SSHException('Remote transport is ignoring rekey requests')
|
||||
|
||||
return ord(payload[0]), msg
|
||||
|
||||
cmd = ord(payload[0])
|
||||
self._log(DEBUG, 'Read packet $%x, length %d' % (cmd, len(payload)))
|
||||
return cmd, msg
|
||||
|
||||
def _set_K_H(self, k, h):
|
||||
"used by a kex object to set the K (root key) and H (exchange hash)"
|
||||
|
|
Loading…
Reference in New Issue