The branch, master has been updated via 469afde919074790f53328b0f2fc3fd8f2971ea8 (commit) from 144f7a489ea5aefcb13aca8a619438f329da3a66 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 469afde919074790f53328b0f2fc3fd8f2971ea8 Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Date: Mon May 28 16:55:11 2012 +0200 Use proper locking of session actions that are critical to being executed in parallel. ----------------------------------------------------------------------- Summary of changes: debian/changelog | 2 + x2go/backends/control/_stdout.py | 93 ++++++++++++++++++++++--------------- x2go/backends/terminal/_stdout.py | 11 ++-- 3 files changed, 62 insertions(+), 44 deletions(-) The diff of changes is: diff --git a/debian/changelog b/debian/changelog index 4a70238..89fff6d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -140,6 +140,8 @@ python-x2go (0.1.2.0-0~x2go1) UNRELEASED; urgency=low keyboard layout _and_ the keyboard variant from the client-side. - Give functionality to the ,,setdpi'' and the ,,dpi'' session profile parameter (setting the DPI allows font scaling). + - Use proper locking of session actions that are critical to being executed + in parallel. * Depend on python-xlib. -- Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Sat, 28 Sep 2012 01:44:21 +0100 diff --git a/x2go/backends/control/_stdout.py b/x2go/backends/control/_stdout.py index e249cc4..f9be7da 100644 --- a/x2go/backends/control/_stdout.py +++ b/x2go/backends/control/_stdout.py @@ -35,6 +35,7 @@ import string import random import re import locale +import threading from gevent import socket @@ -127,8 +128,6 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient): self._server_features = None - self.locked = False - if logger is None: self.logger = log.X2goLogger(loglevel=loglevel) else: @@ -155,6 +154,8 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient): self.published_applications_no_submenus = published_applications_no_submenus self._already_querying_published_applications = False + self._transport_lock = threading.Lock() + def get_hostname(self): return self.hostname @@ -172,41 +173,57 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient): def _x2go_sftp_put(self, local_path, remote_path): - self.logger('sFTP-put: %s -> %s:%s' % (os.path.normpath(local_path), self.remote_peername(), remote_path), loglevel=log.loglevel_DEBUG) - try: - while self.sftp_client is None: - gevent.sleep(.1) - self.sftp_client.put(os.path.normpath(local_path), remote_path) - except x2go_exceptions.SSHException: - # react to connection dropped error for SSH connections - raise x2go_exceptions.X2goControlSessionException('The SSH connection was dropped during an SFTP put action.') + ssh_transport = self.get_transport() + self._transport_lock.acquire() + if ssh_transport and ssh_transport.is_authenticated(): + self.logger('sFTP-put: %s -> %s:%s' % (os.path.normpath(local_path), self.remote_peername(), remote_path), loglevel=log.loglevel_DEBUG) + self.sftp_client = paramiko.SFTPClient.from_transport(ssh_transport) + try: + self.sftp_client.put(os.path.normpath(local_path), remote_path) + except x2go_exceptions.SSHException, socket.error: + # react to connection dropped error for SSH connections + self._transport_lock.release() + raise x2go_exceptions.X2goControlSessionException('The SSH connection was dropped during an SFTP put action.') + self.sftp_client = None + self._transport_lock.release() def _x2go_sftp_write(self, remote_path, content): - self.logger('sFTP-write: opening remote file %s on host %s for writing' % (remote_path, self.remote_peername()), loglevel=log.loglevel_DEBUG) - try: - while self.sftp_client is None: - gevent.sleep(.1) - remote_fileobj = self.sftp_client.open(remote_path, 'w') - self.logger('sFTP-write: writing content: %s' % content, loglevel=log.loglevel_DEBUG_SFTPXFER) - remote_fileobj.write(content) - remote_fileobj.close() - except x2go_exceptions.SSHException: - self.logger('sFTP-write: opening remote file %s on host %s failed' % (remote_path, self.remote_peername()), loglevel=log.loglevel_WARN) + ssh_transport = self.get_transport() + self._transport_lock.acquire() + if ssh_transport and ssh_transport.is_authenticated(): + self.logger('sFTP-write: opening remote file %s on host %s for writing' % (remote_path, self.remote_peername()), loglevel=log.loglevel_DEBUG) + self.sftp_client = paramiko.SFTPClient.from_transport(ssh_transport) + try: + remote_fileobj = self.sftp_client.open(remote_path, 'w') + self.logger('sFTP-write: writing content: %s' % content, loglevel=log.loglevel_DEBUG_SFTPXFER) + remote_fileobj.write(content) + remote_fileobj.close() + except x2go_exceptions.SSHException, socket.error: + self._transport_lock.release() + self.logger('sFTP-write: opening remote file %s on host %s failed' % (remote_path, self.remote_peername()), loglevel=log.loglevel_WARN) + self.sftp_client = None + self._transport_lock.release() def _x2go_sftp_remove(self, remote_path): - self.logger('sFTP-write: removing remote file %s on host %s' % (remote_path, self.remote_peername()), loglevel=log.loglevel_DEBUG) - while self.sftp_client is None: - gevent.sleep(.1) - self.sftp_client.remove(remote_path) + ssh_transport = self.get_transport() + self._transport_lock.acquire() + if ssh_transport and ssh_transport.is_authenticated(): + self.logger('sFTP-write: removing remote file %s on host %s' % (remote_path, self.remote_peername()), loglevel=log.loglevel_DEBUG) + self.sftp_client = paramiko.SFTPClient.from_transport(ssh_transport) + try: + self.sftp_client.remove(remote_path) + except x2go_exceptions.SSHException, socket.error: + self._transport_lock.release() + self.logger('sFTP-write: removing remote file %s on host %s failed' % (remote_path, self.remote_peername()), loglevel=log.loglevel_WARN) + self.sftp_client = None + self._transport_lock.release() def _x2go_exec_command(self, cmd_line, loglevel=log.loglevel_INFO, timeout=20, **kwargs): - while self.locked: - gevent.sleep(.1) + self._transport_lock.acquire() - self.locked = True _retval = None if type(cmd_line) == types.ListType: @@ -214,11 +231,10 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient): else: cmd = cmd_line ssh_transport = self.get_transport() - if ssh_transport is not None: + if ssh_transport and ssh_transport.is_authenticated(): timer = gevent.Timeout(timeout) timer.start() - self.sftp_client = None try: self.logger("executing command on X2Go server ,,%s'': %s" % (self.profile_name, _rerewrite_blanks(cmd)), loglevel) _retval = self.exec_command(_rewrite_password(cmd, user=self.get_transport().get_username(), password=self._session_password), **kwargs) @@ -226,42 +242,40 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient): self.session_died = True if self.sshproxy_session: self.sshproxy_session.stop_thread() - self.locked = False + self._transport_lock.release() raise x2go_exceptions.X2goControlSessionException('the X2Go control session has died unexpectedly') except EOFError: self.session_died = True if self.sshproxy_session: self.sshproxy_session.stop_thread() - self.locked = False + self._transport_lock.release() raise x2go_exceptions.X2goControlSessionException('the X2Go control session has died unexpectedly') except x2go_exceptions.SSHException: self.session_died = True if self.sshproxy_session: self.sshproxy_session.stop_thread() - self.locked = False + self._transport_lock.release() raise x2go_exceptions.X2goControlSessionException('the X2Go control session has died unexpectedly') except gevent.timeout.Timeout: self.session_died = True if self.sshproxy_session: self.sshproxy_session.stop_thread() - self.locked = False + self._transport_lock.release() raise x2go_exceptions.X2goControlSessionException('the X2Go control session command timed out') except socket.error: self.session_died = True if self.sshproxy_session: self.sshproxy_session.stop_thread() - self.locked = False + self._transport_lock.release() raise x2go_exceptions.X2goControlSessionException('the X2Go control session has died unexpectedly') finally: - self.locked = False timer.cancel() - self.sftp_client = paramiko.SFTPClient.from_transport(ssh_transport) else: - self.locked = False raise x2go_exceptions.X2goControlSessionException('the X2Go control session is not connected') - return _retval + self._transport_lock.release() + return _retval @property def _x2go_server_features(self): @@ -598,6 +612,9 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient): self._session_auth_rsakey = None + # in any case, release out internal transport lock + self._transport_lock.release() + try: if self.get_transport() is not None: still_active = self.get_transport().is_active() diff --git a/x2go/backends/terminal/_stdout.py b/x2go/backends/terminal/_stdout.py index ce80d32..066db33 100644 --- a/x2go/backends/terminal/_stdout.py +++ b/x2go/backends/terminal/_stdout.py @@ -33,6 +33,7 @@ import gevent import cStringIO import copy import shutil +import threading # Python X2Go modules import x2go.rforward as rforward @@ -339,6 +340,7 @@ class X2goTerminalSessionSTDOUT(object): else: self.session_info = info_backend() + self._share_local_folder_lock = threading.Lock() self._cleaned_up = False def __del__(self): @@ -698,9 +700,7 @@ class X2goTerminalSessionSTDOUT(object): _x2go_key_bundle = _tmp_io_object.getvalue() # if there is another call to this method currently being processed, wait for that one to finish - while self._share_local_folder_busy: - gevent.sleep(.1) - self._share_local_folder_busy = True + self._share_local_folder_lock.acquire() try: self.control_session._x2go_sftp_write(_x2go_key_fname, _x2go_key_bundle) @@ -762,10 +762,9 @@ class X2goTerminalSessionSTDOUT(object): self.logger('x2gomountdirs output is: %s' % _stdout, log.loglevel_NOTICE) except: + self._share_local_folder_lock.release() raise - finally: - # allow sharing of other folders again - self._share_local_folder_busy = False + self._share_local_folder_lock.release() if len(_stdout) >= 6 and _stdout[5].endswith('ok'): return True hooks/post-receive -- python-x2go.git (Python X2Go Client API) This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "python-x2go.git" (Python X2Go Client API).