xpra icon
Bug tracker and wiki

Opened 9 months ago

Closed 6 weeks ago

#1400 closed enhancement (fixed)

clipboard rate limit

Reported by: alas Owned by: alas
Priority: critical Milestone: 2.1
Component: clipboard Version: trunk
Keywords: Cc:


Thinking about possible ways to handle the clipboard with html5 client, it might be useful to treat as a greedy client and sync with the primary clipboard. That said, users highlighting things left and right and so on might trigger some of the client lock ups that have been seen when clipboard sync'ing becomes overloaded.

It might also be useful to be able to set the rate limiting to include rate/size of content. (Or maybe not...)

Attachments (1)

throttle-clipboard.patch (3.8 KB) - added by Antoine Martin 5 months ago.
throttle the clipboard in the server source

Download all attachments as: .zip

Change History (12)

comment:1 Changed 9 months ago by Antoine Martin

Milestone: 2.0
Status: newassigned

Especially if "greedy" clients (ie: OSX, but maybe also the HTML5 client) sync with the PRIMARY clipboard.

comment:2 Changed 8 months ago by Antoine Martin

Priority: minormajor

This may also be useful for more gracefully handling clipboard managers, see ticket:276#comment:28.

comment:3 Changed 7 months ago by Antoine Martin

Milestone: 2.02.1

Clipboard issues have only just been fixed, I am not feeling adventurous enough to make more changes just yet!

comment:4 Changed 7 months ago by Antoine Martin

This may also help with the html5 clipboard (#1461) since we synchronize the primary selection, which can get updated very rapidly.

Changed 5 months ago by Antoine Martin

Attachment: throttle-clipboard.patch added

throttle the clipboard in the server source

comment:5 Changed 5 months ago by Antoine Martin

The somewhat naive approach taken in the patch above found the following problems:

  • an earlier version failed to call "compress_clipboard" in the non-throttled case and caused the whole server to deadlock - not sure why, this shouldn't happen and needs investigating
  • this throttling does work but causes the packets to accumulate rapidly: easily queuing up hundreds of mostly useless packets

We should be smarter about where and how we throttle:

  • the "clipboard change" event usually triggers everything else
  • if we throttle it, maybe we need to also be able to cancel it when the token ownership changes... (using the token event counter)

comment:6 Changed 5 months ago by Antoine Martin

Owner: changed from Antoine Martin to alas
Status: assignednew

Done in r15603. We throttle the sending of the clipboard token.
The token is sent whenever:

  • the clipboard contents change and the client wants the updated contents, ie: "greedy" clients like macosx and html5
  • we didn't own the clipboard before and we need to tell the other end that we now do - this isn't throttled because it doesn't need to be (happens more rarely and would easily create race conditions if we did throttle it)

Ideally, we would only throttle the clipboard tokens when the sending is expensive (for "greedy" clients with the "want-targets" attribute), but this code throttles all "greedy" clients... including MS Windows clients. This could be improved.

By default the delay is 100ms (since r15604), tunable via the XPRA_DELAY_SEND_TOKEN env var.
I have kept the "more than XX clipboard requests per second!" guard that disables the clipboard with the same default

XPRA_CLIPBOARD_LIMIT=20, but it shouldn't be possible to trip this code with the default settings.

With "-d clipboard", the server log now shows:

clipboard: CLIPBOARD owner_changed, enabled=True, can-send=True, can-receive=True, have_token=False, greedy_client=True, block_owner_change=False
schedule_emit_token() elapsed=11
clipboard: CLIPBOARD owner_changed, enabled=True, can-send=True, can-receive=True, have_token=False, greedy_client=True, block_owner_change=False
clipboard: CLIPBOARD owner_changed, enabled=True, can-send=True, can-receive=True, have_token=False, greedy_client=True, block_owner_change=False
clipboard: CLIPBOARD owner_changed, enabled=True, can-send=True, can-receive=True, have_token=False, greedy_client=True, block_owner_change=False
send clipboard token: CLIPBOARD

The first "owner_changed" triggers "schedule_emit_token" and we have time to process 3 more "owner_changed" before we actually send the token.

To trigger those fast changes to the clipboard contents, you can select text in an editor (ie: gedit) and drag the mouse to change the selection, or you can use this shell scriptlet in an xterm:

while true; do
    date | xclip -selection CLIPBOARD -i;
    sleep 0.05;

@afarr: this works fine for me... not that this means much. Can you break it?

comment:7 Changed 2 months ago by Antoine Martin

Priority: majorcritical

this is an important feature - please test

comment:8 Changed 2 months ago by Antoine Martin

Summary: It might be useful to be able to set a clipboard rate limitclipboard rate limit

comment:9 Changed 7 weeks ago by alas

Made some time for some relatively quick and preliminary tests... figuring that highlighting more and more and more would pose the issue for a rate limited primary clipboard.

With a 2.2 r16595 fedora 25 server running firefox & an xterm as start-childs, and using chrome 59 on windows 7 for html5 client - I found it looked pretty good when copying relatively small bits of text.
When I try to copy enough so that I have to use the mouse wheel to scroll down the page while holding the left-click, however... I wind up with what I assume is an excess of contents, and I'm assuming that this is the result of the limiting, and therefore belongs here, rather than an issue with UTF-8 which should go into #1461 (since the amount of text, and therefore the amount of highlighting, seems to be the difference between functioning and failing).

Anyway, I found that maxymlyn must've left a wiki page on my browser, so I was using: https://en.wikipedia.org/wiki/German_re-armament#Conjectures

I copied a relatively random bit of text:

The Spanish Civil War 1936–1939 would provide an ideal testing ground for the proficiency of the new weapons produced by the German factories during the re-armament years. Many aeronautical bombing techniques (i.e. dive bombing) were tested by the Condor Legion German expeditionary forces against the Republican Government on Spanish soil with the permission of Generalísimo Francisco Franco. Hitler insisted, however, that his long-term designs were peaceful, a strategy labelled as "Blumenkrieg" (Flower War).[12]

Re-armament in the 1930s saw the development of different theories of how to prepare the German economy for total war. The first amongst these was 'defence in depth' which was put forward by Georg Thomas. He suggested that the German economy needed to achieve Autarky (or self-sufficiency) and one of the main proponents behind this was I.G. Farben. Hitler never put his full support behind Autarky and aimed for the development of 'defence in breadth' which espoused the development of the armed forces in all areas and was not concerned with preparing the German economy for war.[citation needed][disputed (for: conflicting information without verification)  – discuss]

In any event, Hitler could boast on 26 September 1938 in the Berlin Sportpalast that after giving orders to rearm the Wehrmacht he could "openly admit: we rearmed to an extent the like of which the world has not yet seen. [13]"

Since World War II, both academics and laypeople have discussed the extent to which German re-armament was an open secret among national governments. A likely element in the thinking of some Western leaders was the willingness to condone a rearmed and powerful anticommunist Germany as a potential bulwark against the emergence of the USSR which, under Stalin, had successfully undergone a la

But attempting to paste it, I get this output.


... which does look like hexadecimal and is something we've been seeing not just with clipboard contents but even when attempting to parse links that are too long (which seems to argue that maybe it is a UTF-8 issue?).

I didn't have the -d clipboard running at the time, but when I repeated the experiment (with a much longer bit of text, which would seem to be less useful for narrowing down where the limit might be hit) I saw the following logs server-side.

2017-08-01 17:32:21,257 clipboard: PRIMARY owner_changed, enabled=True, can-send=True, can-receive=True, have_token=False, greedy_client=True, block_owner_change=False
2017-08-01 17:32:21,258 schedule_emit_token() elapsed=46513 (max=100)
2017-08-01 17:32:21,259 send clipboard token: PRIMARY
2017-08-01 17:32:21,259 client wants targets with the token, querying TARGETS
2017-08-01 17:32:21,259 get_contents(TARGETS,<function got_targets at 0x7f7b72a60d70>) selection=PRIMARY, enabled=True, can-send=True
2017-08-01 17:32:21,260 remove_block: PRIMARY
2017-08-01 17:32:21,262 got_targets(<gtk.Clipboard object at 0x7f7b723d8c80 (GtkClipboard at 0x55b006cf2900)>, ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'text/html', 'text/_moz_htmlcontext', 'text/_moz_htmlinfo', 'UTF8_STRING', 'COMPOUND_TEXT', 'TEXT', 'STRING', 'text/x-moz-url-priv'), (None,))
2017-08-01 17:32:21,262 got_targets for selection PRIMARY: ATOM, 32, ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'text/html', 'text/_moz_htmlcontext', 'text/_moz_htmlinfo', 'UTF8_STRING', 'COMPOUND_TEXT', 'TEXT', 'STRING', 'text/x-moz-url-priv')
2017-08-01 17:32:21,262 get_contents(UTF8_STRING,<function got_contents at 0x7f7b72a60cf8>) selection=PRIMARY, enabled=True, can-send=True
2017-08-01 17:32:21,263 unpack <gtk.Clipboard object at 0x7f7b723d8c80 (GtkClipboard at 0x55b006cf2900)>: <type 'gtk.SelectionData'>
2017-08-01 17:32:21,263 unpack: <GtkSelectionData at 0x55b00726ef00>
2017-08-01 17:32:21,263 unpack(..) type=UTF8_STRING, format=8, data=<type 'str'>:8371
2017-08-01 17:32:21,264 got_contents for selection PRIMARY: UTF8_STRING, 8, " The Heinkel He 111\n\n, one of the technologic .. cting the military restrictions set forth by th"
2017-08-01 17:32:21,264 _do_munge_raw_selection_to_wire(UTF8_STRING, UTF8_STRING, 8, <type 'str'>:8371)
2017-08-01 17:32:21,264 sending token with target data: ('UTF8_STRING', 'UTF8_STRING', 8, 'bytes', Compressible(clipboard: UTF8_STRING / 8: 8371 bytes), True, False)
2017-08-01 17:32:21,264 clipboard_nesting_check(sending, clipboard-token, X11ServerSource(1 : Protocol(tcp websocket: <-
2017-08-01 17:32:23,158 clipboard: CLIPBOARD owner_changed, enabled=True, can-send=True, can-receive=True, have_token=False, greedy_client=True, block_owner_change=False
2017-08-01 17:32:23,159 schedule_emit_token() elapsed=47995 (max=100)
2017-08-01 17:32:23,159 send clipboard token: CLIPBOARD
2017-08-01 17:32:23,160 client wants targets with the token, querying TARGETS
2017-08-01 17:32:23,160 get_contents(TARGETS,<function got_targets at 0x7f7b72a60b18>) selection=CLIPBOARD, enabled=True, can-send=True
2017-08-01 17:32:23,161 remove_block: CLIPBOARD
2017-08-01 17:32:23,163 got_targets(<gtk.Clipboard object at 0x7f7b723d8af0 (GtkClipboard at 0x55b006cf2880)>, ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'SAVE_TARGETS', 'text/html', 'text/_moz_htmlcontext', 'text/_moz_htmlinfo', 'UTF8_STRING', 'COMPOUND_TEXT', 'TEXT', 'STRING', 'text/x-moz-url-priv'), (None,))
2017-08-01 17:32:23,164 got_targets for selection CLIPBOARD: ATOM, 32, ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'SAVE_TARGETS', 'text/html', 'text/_moz_htmlcontext', 'text/_moz_htmlinfo', 'UTF8_STRING', 'COMPOUND_TEXT', 'TEXT', 'STRING', 'text/x-moz-url-priv')
2017-08-01 17:32:23,164 get_contents(UTF8_STRING,<function got_contents at 0x7f7b72a600c8>) selection=CLIPBOARD, enabled=True, can-send=True
2017-08-01 17:32:23,165 unpack <gtk.Clipboard object at 0x7f7b723d8af0 (GtkClipboard at 0x55b006cf2880)>: <type 'gtk.SelectionData'>
2017-08-01 17:32:23,165 unpack: <GtkSelectionData at 0x55b00726eec0>
2017-08-01 17:32:23,166 unpack(..) type=UTF8_STRING, format=8, data=<type 'str'>:8371
2017-08-01 17:32:23,166 got_contents for selection CLIPBOARD: UTF8_STRING, 8, " The Heinkel He 111\n\n, one of the technologic .. cting the military restrictions set forth by th"
2017-08-01 17:32:23,166 _do_munge_raw_selection_to_wire(UTF8_STRING, UTF8_STRING, 8, <type 'str'>:8371)
2017-08-01 17:32:23,166 sending token with target data: ('UTF8_STRING', 'UTF8_STRING', 8, 'bytes', Compressible(clipboard: UTF8_STRING / 8: 8371 bytes), True, False)
2017-08-01 17:32:23,167 clipboard_nesting_check(sending, clipboard-token, X11ServerSource(1 : Protocol(tcp websocket: <-

... then again, maybe the mention of 'unpack'ing means the large contents are being somehow compressed/packed? (probably not, but it's a thought).

I'll try to turn on the clipboard_gtk.py tool soon and watch as I highlight portions of text (well, try to check over progressively larger blocks of highlit text) to see if there's some point where the text converts into apparent base 128 numerical values or something at some point.
In the meantime, I'll hand this back to look at.

comment:10 Changed 7 weeks ago by Antoine Martin

But attempting to paste it, I get this output.
... which does look like hexadecimal

That's decimal (0-9), hexadecimal is 0-9 + A-F.

That was a different bug - fixed in r16600, nothing to do with rate limiting.
This was caused indirectly by the zero copy changes of ticket:1424#comment:1.

comment:11 Changed 6 weeks ago by alas

Resolution: fixed
Status: newclosed

Hmm... I suppose I meant that I thought it was base 128 (but my fondness for hexadecimal got the better of me?).

In any case, the issue is fixed when testing with a 2.2 r16657 fedora 25 server (testing with windows 7 & chrome 59 in this case).

Since I couldn't come up with any hyperactive clipboard scenario that so much as phased your html5 clipboard, I'll call the rate limiting fixed and close this. Nicely done.

Note: See TracTickets for help on using tickets.