Related to #41.
Create a UUID for each clipboard helper and add it to a root window property. Clients and servers forward their list of UUIDs to the other end, which then adds those to the root window property. If any duplicates are found, we have a loop.
Another way of dealing with this is to set a random token on startup, prevent this token from ever being sent across, then looking for it at the other end. Any other clipboard synchronization tool will copy it, then we know we have a loop.
work in progress patch
Done in r18229 (see commit message): we use a token which is never forwarded, then check for its presence at the other end.
Still TODO:
Notifications and more done in r18230.
Keeping this ticket assigned to me as I have seen shadow server hangs in the clipboard code, which may be caused / made worse / related to this.
Crashes and other problems should be gone as of r18248.
@maxmylyn: this ticket should ensure that we can coexist with other clipboard synchronization tools (ie: virtualbox, synergy, etc) and deal with it much more gracefully: disabling the clipboard and showing a notification to the user. Feel free to close.
Excellent - noted.
Closing
Hit a clipboard loop which was not detected: #1814
Finally got a clean reproducer without ssh start:
xpra shadow :1 --bind-tcp=0.0.0.0:10000 --no-daemon -d clipboard
From a win32 client which has clipboard synchronization already active through synergy, this usually works:
xpra attach tcp://192.168.1.8:10000/ -d clipboard
But this usually causes the server to hang:
xpra attach ssh://192.168.1.8/1 -d clipboard
Some of the weird exceptions I hit using these commands, or using a remote start via ssh: xpra start ssh://localhost/1
:
Warning: more than 30 clipboard requests per second! ... Warning: more than 30 clipboard requests per second! limit sustained for more than 3 seconds, the clipboard is now disabled
do_selection_get(<GtkSelectionData at 0x7fff027517c0>, 0, 45997266) selection=CLIPBOARD Traceback (most recent call last): File "/usr/lib64/python2.7/site-packages/xpra/clipboard/clipboard_base.py", line 332, in _get_clipboard_from_remote_handler log("get clipboard from remote handler id=%s", request_id) File "/usr/lib64/python2.7/site-packages/xpra/log.py", line 392, in __call__ self.log(logging.DEBUG, msg, *args, **kwargs) File "/usr/lib64/python2.7/site-packages/xpra/log.py", line 388, in log global_logging_handler(self.logger.log, level, msg, *args, **kwargs) File "/usr/lib64/python2.7/site-packages/xpra/log.py", line 132, in standard_logging log(level, msg, *args, **kwargs) File "/usr/lib64/python2.7/logging/__init__.py", line 1231, in log self._log(level, msg, args, **kwargs) File "/usr/lib64/python2.7/logging/__init__.py", line 1285, in _log record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra) File "/usr/lib64/python2.7/logging/__init__.py", line 1259, in makeRecord rv = LogRecord(name, level, fn, lno, msg, args, exc_info, func) File "/usr/lib64/python2.7/logging/__init__.py", line 263, in __init__ if (args and len(args) == 1 and isinstance(args[0], collections.Mapping) File "/usr/lib64/python2.7/abc.py", line 132, in __instancecheck__ if subclass is not None and subclass in cls._abc_cache: File "/usr/lib64/python2.7/_weakrefset.py", line 72, in __contains__ wr = ref(item) RuntimeError: maximum recursion depth exceeded remote selection fetch timed out or empty
error running cleanup <function cleanup_tcp_socket at 0x7f41d31ec668> Traceback (most recent call last): File "/usr/lib64/python2.7/site-packages/xpra/scripts/server.py", line 33, in run_cleanups c() File "/usr/lib64/python2.7/site-packages/xpra/server/socket_util.py", line 129, in cleanup_tcp_socket log.info("closing %s socket %s:%s", socktype.lower(), host, iport) File "/usr/lib64/python2.7/site-packages/xpra/log.py", line 397, in info self.log(logging.INFO, msg, *args, **kwargs) File "/usr/lib64/python2.7/site-packages/xpra/log.py", line 388, in log global_logging_handler(self.logger.log, level, msg, *args, **kwargs) File "/usr/lib64/python2.7/site-packages/xpra/log.py", line 132, in standard_logging log(level, msg, *args, **kwargs) File "/usr/lib64/python2.7/logging/__init__.py", line 1231, in log self._log(level, msg, args, **kwargs) File "/usr/lib64/python2.7/logging/__init__.py", line 1285, in _log record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra) File "/usr/lib64/python2.7/logging/__init__.py", line 1259, in makeRecord rv = LogRecord(name, level, fn, lno, msg, args, exc_info, func) File "/usr/lib64/python2.7/logging/__init__.py", line 285, in __init__ self.threadName = threading.current_thread().name File "/usr/lib64/python2.7/threading.py", line 1157, in currentThread return _DummyThread() File "/usr/lib64/python2.7/threading.py", line 1125, in __init__ Thread.__init__(self, name=_newname("Dummy-%d")) File "/usr/lib64/python2.7/threading.py", line 683, in __init__ self.__started = Event() File "/usr/lib64/python2.7/threading.py", line 553, in Event return _Event(*args, **kwargs) File "/usr/lib64/python2.7/threading.py", line 565, in __init__ _Verbose.__init__(self, verbose) RuntimeError: maximum recursion depth exceeded in __instancecheck__
Another interesting data point is that switching to schedule_emit_token
for all owner change events makes things worse.
Meh. Now that the clipboard uses native API calls (#812), this no longer causes crashes. I don't think that the loop detection code works properly, so maybe we should just remove it?
this ticket has been moved to: https://github.com/Xpra-org/xpra/issues/1312