~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

[merge] bzr.dev 1807

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
import os
23
23
import random
24
24
import re
 
25
import select
25
26
import stat
26
27
import subprocess
27
28
import sys
302
303
            # What specific errors should we catch here?
303
304
            pass
304
305
 
 
306
 
305
307
class SFTPTransport (Transport):
306
308
    """
307
309
    Transport implementation for SFTP access.
887
889
nvuQES5C9BMHjF39LZiGH1iLQy7FgdHyoP+eodI7
888
890
-----END RSA PRIVATE KEY-----
889
891
"""
890
 
    
891
 
 
892
 
class SingleListener(threading.Thread):
 
892
 
 
893
 
 
894
class SocketListener(threading.Thread):
893
895
 
894
896
    def __init__(self, callback):
895
897
        threading.Thread.__init__(self)
899
901
        self._socket.bind(('localhost', 0))
900
902
        self._socket.listen(1)
901
903
        self.port = self._socket.getsockname()[1]
902
 
        self.stop_event = threading.Event()
903
 
 
904
 
    def run(self):
905
 
        s, _ = self._socket.accept()
906
 
        # now close the listen socket
907
 
        self._socket.close()
908
 
        try:
909
 
            self._callback(s, self.stop_event)
910
 
        except socket.error:
911
 
            pass #Ignore socket errors
912
 
        except Exception, x:
913
 
            # probably a failed test
914
 
            warning('Exception from within unit test server thread: %r' % x)
 
904
        self._stop_event = threading.Event()
915
905
 
916
906
    def stop(self):
917
 
        self.stop_event.set()
 
907
        # called from outside this thread
 
908
        self._stop_event.set()
918
909
        # use a timeout here, because if the test fails, the server thread may
919
910
        # never notice the stop_event.
920
911
        self.join(5.0)
 
912
        self._socket.close()
 
913
 
 
914
    def run(self):
 
915
        while True:
 
916
            readable, writable_unused, exception_unused = \
 
917
                select.select([self._socket], [], [], 0.1)
 
918
            if self._stop_event.isSet():
 
919
                return
 
920
            if len(readable) == 0:
 
921
                continue
 
922
            try:
 
923
                s, addr_unused = self._socket.accept()
 
924
                # because the loopback socket is inline, and transports are
 
925
                # never explicitly closed, best to launch a new thread.
 
926
                threading.Thread(target=self._callback, args=(s,)).start()
 
927
            except socket.error, x:
 
928
                sys.excepthook(*sys.exc_info())
 
929
                warning('Socket error during accept() within unit test server'
 
930
                        ' thread: %r' % x)
 
931
            except Exception, x:
 
932
                # probably a failed test; unit test thread will log the
 
933
                # failure/error
 
934
                sys.excepthook(*sys.exc_info())
 
935
                warning('Exception from within unit test server thread: %r' % 
 
936
                        x)
921
937
 
922
938
 
923
939
class SFTPServer(Server):
941
957
        """StubServer uses this to log when a new server is created."""
942
958
        self.logs.append(message)
943
959
 
944
 
    def _run_server(self, s, stop_event):
 
960
    def _run_server(self, s):
945
961
        ssh_server = paramiko.Transport(s)
946
962
        key_file = os.path.join(self._homedir, 'test_rsa.key')
947
 
        file(key_file, 'w').write(STUB_SERVER_KEY)
 
963
        f = open(key_file, 'w')
 
964
        f.write(STUB_SERVER_KEY)
 
965
        f.close()
948
966
        host_key = paramiko.RSAKey.from_private_key_file(key_file)
949
967
        ssh_server.add_server_key(host_key)
950
968
        server = StubServer(self)
954
972
        event = threading.Event()
955
973
        ssh_server.start_server(event, server)
956
974
        event.wait(5.0)
957
 
        stop_event.wait(30.0)
958
975
    
959
976
    def setUp(self):
960
977
        global _ssh_vendor
965
982
            self._server_homedir = self._homedir
966
983
        self._root = '/'
967
984
        # FIXME WINDOWS: _root should be _server_homedir[0]:/
968
 
        self._listener = SingleListener(self._run_server)
 
985
        self._listener = SocketListener(self._run_server)
969
986
        self._listener.setDaemon(True)
970
987
        self._listener.start()
971
988
 
998
1015
        super(SFTPServerWithoutSSH, self).__init__()
999
1016
        self._vendor = 'loopback'
1000
1017
 
1001
 
    def _run_server(self, sock, stop_event):
 
1018
    def _run_server(self, sock):
1002
1019
        class FakeChannel(object):
1003
1020
            def get_transport(self):
1004
1021
                return self