Xpra-org / xpra

Persistent remote applications for X11; screen sharing for X11, MacOS and MSWindows.
https://xpra.org/
GNU General Public License v2.0
1.82k stars 157 forks source link

quic transport #3376

Closed totaam closed 1 year ago

totaam commented 2 years ago

QUIC could easily replace the old UDP transport. There are frameworks and APIs that wrap QUIC with easy to use callbacks, like https://github.com/aiortc/aioquic documentation (see also https://github.com/MagicStack/uvloop) We would get HTTP/3 and encryption almost for free and a reliable event based framework for managing connection state.

Examples include an http3 server and clients, etc..

The re-send / packet-drop callbacks could easily re-use the techniques that were used for UDP (#639) which was removed in 2022238ababa40382d2b8d6b019fb2d757ec9955.


Worth noting that aioquic requires Python 3.7 or better, and the OpenSSL development headers so this won't be available on RHEL 8.

totaam commented 2 years ago

aioquic is not available in Fedora and the number of dependencies required to run the http3 server example is a little bit ridiculous: python3-wsproto, python3-httpbin, python3-asgiref, python3-starlette and python3-aiofiles. Not counting all the dependencies that each one of these packages brings...

totaam commented 2 years ago

It gets worse since we also need to run the GTK main loop until we can drop GTK (#1995). There are various ways of doing this:

And perhaps soon in pygobject directly: Implement asyncio event loop based on glib

Next, creating asyncio sockets requires using a specific API: asyncio.loop.create_datagram_endpoint / loop.create_connection, which means that socket sharing is going to be more difficult to implement.

This may help in bridging with the rest of the code:

TijZwa commented 1 year ago

I've done some testing with Aioquic. Basically I've just glued asyncio with aioquic to the existing codebase. The main issue is starting a new main loop inside a thread, inside the existing GTK loop. Also the list of dependencies is way too big (starlette and what not).

The source of aioquic seems pretty neat. I think the best way forward is to use this code as an example to implement our own low-level implementation of a http/3 quic server.

https://github.com/aiortc/aioquic/tree/main/src/aioquic

totaam commented 1 year ago

as an example to implement our own low-level implementation of a http/3 quic server

Yes! This part of the library looks really clean and, at first glance, without too many dependencies, only things like https://github.com/aiortc/pylsqpack Gio supports UDP so there is no reason why we can't use the GTK main loop for handling packet events.

totaam commented 1 year ago

We need an asyncio event loop: https://github.com/aiortc/aioquic/blob/444be09157aed3c81881d18647484165dd07139c/src/aioquic/asyncio/server.py#L202

The patches for pygobject are still languishing as a PR and asyncio-glib is unmaintained.

And gbulb has had no update since earlier this year.

Then there's also glibcoro: glibcoro makes the GLib / GTK event loop compatible with Python’s asyncio

Meanwhile, this answer: https://stackoverflow.com/a/26719999/428751 suggests running the aio part in a separate thread. Downside is: _One does need to be careful, however, to use thread-safe functions to communicate between the GUI (main) thread and the asyncio thread. This means using loop.call_soon_threadsafe or asyncio.run_coroutine_threadsafe to submit things to asyncio from GTK, and GLib.idleadd to submit things to GTK from asyncio.

Decisions!

totaam commented 1 year ago

There's still a lot to do:


xpra start --no-daemon -d quic --start=xterm
    --bind-tcp=0.0.0.0:10000
    --bind-quic=localhost:20000 --ssl-cert=./cert.pem --ssl-key=./key.pem

Allows http3 clients to connect:

./examples/http3_client.py "https://localhost:20000/Sessions?hello=foo&bar=2" -k -v --output-dir=./output

Apparently, chrome needs to be told to use the QUIC protocol

totaam commented 1 year ago

As of d4c7fc8989d8a492b0f481fa5a092b3f875e7a35, I can connect via quic using a self signed cert:

xpra start --bind-quic=localhost:20000 --start=xterm :100 \
    --ssl-cert=./cert.pem --ssl-key=./key.pem
xpra attach quic://localhost:20000/ --ssl-server-verify-mode=none
totaam commented 1 year ago

As per QUIC Throughput and Fairness over Dual Connectivity:

So running a quic server may require tweaking the kernel parameters:

sysctl -w net.core.rmem_max=26214400
sysctl -w net.core.rmem_default=26214400

On sending audio and video using lossy frames - from RFC9221 which is supported by aioquic:


Also need to figure out how to modify the video encoders for:

totaam commented 1 year ago

Some notes on audio: do we want to use datagrams and rtpjitterbuffer? See How to make rtpjitterbuffer work on a stream without timestamps?

totaam commented 3 months ago

Looks like asyncio integration with support to await Gio async functions is going to be merged! But we'll have to keep the threaded implementation around until all the supported distros ship with the new pygobject... which could take many years.

totaam commented 4 weeks ago

Looks like asyncio will be integrated with pygobject Gio soon: asyncio integration with support to await Gio async functions so we will be able to drop the ugly asyncio_thread workaround in the future.

totaam commented 3 weeks ago

WebTransport can now be used with the html5 client: https://github.com/Xpra-org/xpra-html5/issues/143#issuecomment-2198058969 It would be nice to also support a xpra attach webtransport://host:port/ mode for the Python client.