xpra icon
Bug tracker and wiki

Opened 21 months ago

Last modified 2 months ago

#1312 assigned enhancement

avoid clipboard loops when running nested / sharing sessions

Reported by: Antoine Martin Owned by: Antoine Martin
Priority: minor Milestone: 2.3
Component: clipboard Version: trunk
Keywords: Cc:

Description (last modified by Antoine Martin)

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.

Attachments (1)

clipboard-loops.patch (6.6 KB) - added by Antoine Martin 21 months ago.
work in progress patch

Download all attachments as: .zip

Change History (9)

Changed 21 months ago by Antoine Martin

Attachment: clipboard-loops.patch added

work in progress patch

comment:1 Changed 5 months ago by Antoine Martin

Description: modified (diff)
Milestone: future2.3
Status: newassigned

comment:2 Changed 5 months ago by Antoine Martin

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: #1688
  • maybe clear the magic token after we have verified at the other end
Last edited 5 months ago by Antoine Martin (previous) (diff)

comment:3 Changed 5 months ago by Antoine Martin

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.

comment:4 Changed 5 months ago by Antoine Martin

Owner: changed from Antoine Martin to J. Max Mena
Status: assignednew

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.

comment:5 Changed 5 months ago by J. Max Mena

Resolution: fixed
Status: newclosed

Excellent - noted.

Closing

comment:6 Changed 2 months ago by Antoine Martin

Resolution: fixed
Status: closedreopened

Hit a clipboard loop which was not detected: #1814

comment:7 Changed 2 months ago by Antoine Martin

Owner: changed from J. Max Mena to Antoine Martin
Status: reopenednew

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__

comment:8 Changed 2 months ago by Antoine Martin

Status: newassigned

Another interesting data point is that switching to schedule_emit_token for all owner change events makes things worse.

Note: See TracTickets for help on using tickets.