~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

  • Committer: Robert Collins
  • Date: 2006-07-20 23:55:43 UTC
  • mto: (1874.1.1 bzr.socket-delay)
  • mto: This revision was merged to the branch mainline in revision 1947.
  • Revision ID: robertc@robertcollins.net-20060720235543-b4d001872c2f9884
proof of concept slowsocket wrapper.

Show diffs side-by-side

added added

removed removed

Lines of Context:
940
940
                        x)
941
941
 
942
942
 
 
943
class SocketDelay(object):
 
944
    """A socket decorator to make TCP appear slower.
 
945
 
 
946
    This changes recv, send, and sendall to add a fixed latency to each 
 
947
    python call. It will therefore behave differently to the real underlying
 
948
    TCP stack which may only pay the latency price on each actual roundtrip
 
949
    rather than each packet initiated. We can come closer to the real
 
950
    behaviour by only charging latency for each roundtrip we detect - that is
 
951
    when recv is called, toggle a flag, and insert latency again only when
 
952
    send has been called in the middle. For now though, showing more latency
 
953
    than we have is probably acceptable.
 
954
 
 
955
    Not all methods are implemented, this is deliberate as this class is not
 
956
    a replacement for the builtin sockets layer. fileno is not implemented to
 
957
    prevent the proxy being bypassed.
 
958
    """
 
959
 
 
960
    def __init__(self, sock, latency):
 
961
        self.sock = sock
 
962
        self.latency = latency
 
963
 
 
964
    def close(self):
 
965
        return self.sock.close()
 
966
 
 
967
    def dup(self):
 
968
        return SocketDelay(self.sock.dup(), self.latency)
 
969
 
 
970
    def getpeername(self, *args):
 
971
        return self.sock.getpeername(*args)
 
972
 
 
973
    def getsockname(self, *args):
 
974
        return self.sock.getsockname(*args)
 
975
    
 
976
    def getsockopt(self, *args):
 
977
        return self.sock.getsockopt(*args)
 
978
 
 
979
    def gettimeout(self, *args):
 
980
        return self.sock.gettimeout(*args)
 
981
 
 
982
    def recv(self, *args):
 
983
        data = self.sock.recv(*args)
 
984
        if data:
 
985
            time.sleep(self.latency)
 
986
        return data
 
987
 
 
988
    def sendall(self, *args):
 
989
        time.sleep(self.latency)
 
990
        return self.sock.sendall(*args)
 
991
 
 
992
    def send(self, *args):
 
993
        time.sleep(self.latency)
 
994
        return self.sock.send(*args)
 
995
 
 
996
    def setblocking(self, *args):
 
997
        return self.sock.setblocking(*args)
 
998
 
 
999
    def setsockopt(self, *args):
 
1000
        return self.sock.setsockopt(*args)
 
1001
 
 
1002
    def settimeout(self, *args):
 
1003
        return self.sock.settimeout(*args)
 
1004
 
 
1005
    def shutdown(self, *args):
 
1006
        return self.sock.shutdown(*args)
 
1007
        
 
1008
 
943
1009
class SFTPServer(Server):
944
1010
    """Common code for SFTP server facilities."""
945
1011
 
952
1018
        self._vendor = 'none'
953
1019
        # sftp server logs
954
1020
        self.logs = []
 
1021
        self.add_latency = 0
955
1022
 
956
1023
    def _get_sftp_url(self, path):
957
1024
        """Calculate an sftp url to this server for path."""
961
1028
        """StubServer uses this to log when a new server is created."""
962
1029
        self.logs.append(message)
963
1030
 
 
1031
    def _run_server_entry(self, sock):
 
1032
        """Entry point for all implementations of _run_server.
 
1033
        
 
1034
        If self.add_latency is > 0.000001 then sock is given a latency adding
 
1035
        decorator.
 
1036
        """
 
1037
        if self.add_latency > 0.000001:
 
1038
            sock = SocketDelay(sock, self.add_latency)
 
1039
        return self._run_server(sock)
 
1040
 
964
1041
    def _run_server(self, s):
965
1042
        ssh_server = paramiko.Transport(s)
966
1043
        key_file = pathjoin(self._homedir, 'test_rsa.key')
992
1069
        self._root = '/'
993
1070
        if sys.platform == 'win32':
994
1071
            self._root = ''
995
 
        self._listener = SocketListener(self._run_server)
 
1072
        self._listener = SocketListener(self._run_server_entry)
996
1073
        self._listener.setDaemon(True)
997
1074
        self._listener.start()
998
1075
 
1009
1086
        return 'sftp://127.0.0.1:1/'
1010
1087
 
1011
1088
 
1012
 
 
1013
1089
class SFTPFullAbsoluteServer(SFTPServer):
1014
1090
    """A test server for sftp transports, using absolute urls and ssh."""
1015
1091