-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
xrdp has very low bandwidth on high latency connections that can be mitigated via SSH tunnel #2905
Comments
Hi @vincent-163 An interesting problem, and an interesting network connection. BTW, thanks for taking the time to fill in the report form properly. It saves a lot of time for both of us. A slow connection like this would be down to two things I could think of
Since you've been playing with congestion algorithms, I'm guessing you're aware of these possibilities. Here's a couple of questions for you:-
Thanks. |
Hello! Thanks for the reply.
With Wireguard it's not easy for GFW to distinguish directly between SSH and RDP. I think the trend is very clear: the bandwidth depends solely on the latency between the xrdp server and the direct TCP client it's connected to, and not on the nature of the network.
I'm creating a Windows server so I can test mstsc over a reliable connection. Do you need an xrdp server? I can create a new xrdp server in either US or Europe for you to test. |
Okay, I think I've reproduced the issue with a pair of distant servers on Hetzner Cloud. I installed a Windows server "A" in Europe and an xrdp server in U.S. "B", then connected to the Windows server "A" via mstsc and then connected to the xrdp server "B" via nested mstsc. It was slow. I installed ssh on "A" and connected to the xrdp server "B" via ssh tunnel, and it was fast. The network connection between "A" and "B" is known to be reliable (stable 120ms latency and over 1Gbps bandwidth) and I'm confident with its reproducibility. |
So I found a pair of configuration options in
I set both of them to 10485760. And in journalctl I get:
Then when I connect to this server I get 6.6Mbps. The theoretical bandwidth with 425984 bytes of window size and 250ms round-trip latency is 425984bytes/250ms=13.0Mbps. When the window size is 32768 bytes, the theoretical bandwidth is 1Mbps. This seems to explain the issue with bandwidth. The reason that the buffer is set to 425984 rather than 10485760 bytes seems to be caused by A few things I don't understand:
After thinking about point 2 more carefully I've come up with an explanation. The reason I can think of is pacing. Say you want to send 10MB but you have only 100KB of buffer and the window size is 5MB. Why can window size be bigger than the buffer size? Because the window size represents the amount of data in flight rather than the data to be sent, and it has to be sent smoothly and not in bursts. So rather than sending 5MB at once, you send 100KB, wait 1/50 roundtrip and then send another 100KB. And it's probably for the same reason that the receive buffer is limited to a very small size. What an ordinary program would do in this case is to try to send 5MB first, finds that only 100KB is sent, waits until the socket becomes writable again and sends another 100KB. Why would a program behave as if the window size was only 100KB? It tried to send 5MB first, found only 100KB is sent, then probably waited until a confirmation until it sent another 100KB. I'm not sure how xrdp is designed, but maybe you'll need a buffered implementation of sockets rather than relying on the kernel, especially when the socket buffer size is smaller than the window. While I have been able to mitigate the problem in this case, you probably don't want to expect every user to tweak the kernel params and buffer sizes manually. |
Yup - the buffer size was likely the culprit. You probably only want to increase the transmit buffer size as RDP traffic is normally pretty one-directional. I'll come to the rest of the post later, but I'd first I'll just point out that you can look at the xrdp socket memory with a command like::-
Or use Starting with your last point, I can't see how buffering stuff in xrdp would help at all. We've still get to get through the kernel buffers - there's no way round them. The TCP sending algorithm will block until the data it's just sent has been ACK'd. I could of course be misunderstanding something here, as you raise the very valid point that ssh doesn't seem to need Are you able to look at the socket memory for ssh? That may give us some further clues. |
Had a think about this last night and this morning I've done a bit of poking around. I've found something interesting (i.e. possibly wrong) here:- Lines 439 to 454 in ccee5af
That bit of code is called when the listening socket is set up for On my system, the default value for My default size of 16KB for a socket buffer comes from this kernel setting:- $ sysctl net.ipv4.tcp_wmem net.ipv4.tcp_wmem = 4096 16384 4194304 This gives us an easy way to disable the xrdp code I've linked above, and get xrdp to behave more like sshd. @vincent-163 - when you get a moment, can you take a look at your setting for
If that solves your problem, the simplest thing to do will be to remove this code. Our other major platform is FreeBSD, and for FreeBSD >= 7.0 send buffer auto-sizing is also supported. Search for FreeBSD |
I've done some experimenting of my own, using a virtual router running OPNSense and a traffic shaper to emulate @vincent-163's network above:-
According to iperf3, my bandwidth is only about 40-60 Mbps, owing to the hardware I'm using. If I just connect to xrdp on a vanilla Ubuntu 22.04 I get round about 1mbps, broadly in line with @vincent-163's findings above. The command I can then increase the default buffer size to 32768 using the script #!/bin/sh
TARGET=32768
set -- $(sysctl net.ipv4.tcp_wmem)
if [ $# != 5 ]; then
echo "** Unable to read current SNDBUF settings" >&2
exit 1
fi
min=$3
def=$4
max=$5
if [ $def -lt $TARGET ]; then
def=$TARGET
if [ $def -lt $min ]; then
echo "** Can't set default buffer size below $min">&2
false
elif [ $def -gt $max ]; then
echo "** Can't set default buffer size over $max">&2
false
elif [ $(id -u) -ne 0 ]; then
echo "** Must be root to set default buffer size">&2
false
else
sysctl net.ipv4.tcp_wmem="$min $def $max"
fi
else
echo "** Default send buffer size is already $def" >&2
fi
exit $? After running the script, you MUST restart xrdp, i.e.:-
On my test system, the difference is amazing frankly. According to This has been a problem with xrdp over LFNs for some time I suspect. Thanks to @vincent-163 for helping me find this. Next step is to reproduce this on a devel build and check removing the erroneous code shows the same improvement in performance. In the meantime, the script above should help xrdp performance on WANs for any existing versions. |
Hello! Thanks for pointing out the relevant source code lines and carrying out the experiment. I tried setting the second value of net.ipv4.tcp_wmem to 32768, and it did work as expected: xrdp was using my full bandwidth (30Mbps due to being on a slower connection). I also tried removing the code that you mentioned and recompiling xrdp, and it seems to have the same effect of using all available bandwidth even after I revert the kernel setting changes. I think the cause of the bug is pretty clear now, but maybe you'll want to verify the fix on your side as well. Thanks for your timely response and hint at the location of the problematic code! It was very rewarding to have a bug report taken seriously and eventually leading to a solution. |
Thanks for taking the time to write a decent fault report in the first place - without the ssh observation (which initially seemed inexplicable) I don't think we'd have found this one. I'll do some more testing then put a PR together to close this. I suspect this will fix a few historic issues, so I'll try to hunt those down too. |
xrdp version
0.9.23.1
Detailed xrdp version, build options
Operating system & version
Arch Linux 20240101.0.204074
Installation method
git clone & make install
Which backend do you use?
xorgxrdp-0.9.19
What desktop environment do you use?
any
Environment xrdp running on
A systemd-nspawn container
What's your client?
Windows 11 mstsc
Area(s) with issue?
Network
Steps to reproduce
/var/lib/machines/xrdp
and booted usingsystemd-nspawn -M xrdp -b
:Use
machinectl shell xrdp
to get into the container and dosystemctl start xrdp
to run it. I'm running it in a systemd-nspawn container but the exact way of running xrdp probably doesn't matter.Use msrtc to connect to the server. Install google chrome in the container and play a video. It's very laggy, and the bandwidth is around 1.3Mbps.
Use SSH to connect to the server and set up a tunnel with
-L 33890:127.0.0.1:3389
. Then connect to127.0.0.1:33890
. You get the same desktop but the bandwidth goes up to 80Mbps and the video plays smoothly.✔️ Expected Behavior
Direct msrtc connection should work at least as smoothly as the connection via SSH tunnel, and use up 80Mbps of bandwidth available to xrdp.
❌ Actual Behavior
Direct msrtc connection uses only 1.3Mbps, a tiny fraction of what is possible.
Anything else?
I switched
net.ipv4.tcp_congestion_control
betweencubic
andbbr
and the behavior doesn't change, suggesting it's not a problem with the congestion algorithm used.The text was updated successfully, but these errors were encountered: