I wanted something to hack on tonight, so being the nerd in search of esoterica I wrote a quick implementation of Aquarius, ie. a non-private non-reliable stripped down protocol resembling Gemini on top of UDP.
Aquarius: an emergency lifeboat version of Gemini?
I might move those files later. They're in a stupid place right now.
Anyway, this server now runs aqserv.py on port 1970 and if you download the client (aqget.py) you can try the protocol out. But *PLEASE* remember: this protocol is *significantly* worse than Gemini in almost all cases. Try not to fall in love with it.
UPDATE 2020-07-28: Sean Conner noted that this protocol is vulnerable to amplification attacks. I'll shut down the server in a couple of days. Feel free to experiment until then, but please don't use the server for DDoS! :)
Using Wireshark, I logged the traffic on port 1970 for the command
python aqget.py aquarius://hannuhartikainen.fi/twinlog/2020-07-27_aquarius.gemini
and on port 1965 for the command
SSLKEYFILE=/tmp/sslkeys gemget gemini://hannuhartikainen.fi/twinlog/2020-07-27_aquarius.gemini
to get a comparison of what happens with each protocol.
With Aquarius, it's simple and plain when it works:
1. Client sends plaintext request: aquarius://hannuhartikainen.fi/twinlog/<CRLF>
2. Server sends six UDP packets with plaintext contents.
If all goes well, every packet reaches their destination in the correct order. If not, some 508-byte chunks of the content may be in the wrong order, some may be missing, and the data may be garbled. ¯\_(ツ)_/¯
With Gemini, both TCP and TLS make me scratch my head.
1. SYN
2. SYN+ACK
3. ACK
4. TLS handshake
5. The actual content
6. ACKs after every packet
7. FIN+ACK
8. RST
I feel like I should understand TCP better but I don't. :(
╔══════════════════╦══════════╦════════╗ ║ ║ Aquarius ║ Gemini ║ ╠══════════════════╬══════════╬════════╣ ║ sent packets ║ 1 ║ 11 ║ ╠══════════════════╬══════════╬════════╣ ║ sent bytes ║ 109 ║ 1235 ║ ╠══════════════════╬══════════╬════════╣ ║ received packets ║ 6 ║ 10 ║ ╠══════════════════╬══════════╬════════╣ ║ received bytes ║ 2968 ║ 5427 ║ ╠══════════════════╬══════════╬════════╣ ║ total time (ms) ║ 20 ║ 101 ║ ╚══════════════════╩══════════╩════════╝
The file size is 2700 bytes, which is quite normal for text/gemini. My ping to the server is 16ms.
The maximum "safe" size for UDP payload over IPv4 is 508 bytes, though 1432 (safe for IPv6) probably works almost as well. The response would have *just* fit into two packets with the larger packet size. That would not really affect speed, though, as all the packets are sent as a burst.
NOTE: this comparison is needlessly bad for Gemini as the server has a large RSA certificate.
In this case, Gemini had about 50/50 content/overhead. With connectionless UDP you get much less overhead, until you start to need retries.
But consider where we come from. On the web it's typical to get 2.7MB or more of overhead (SPA, tracking scripts, you name it) for 2700 bytes of text content. Web pages don't load in 100 milliseconds. I'm happy if they load in 2 seconds.
We get confidentiality and integrity in this case for about 3KB of traffic and 80 milliseconds. It's a ridiculously good deal.
Still, if I wanted a battery-powered embedded server I'd much rather have Aquarius than Gemini. But realistically I'm browsing text content on a laptop or a phone. The main power consumption comes from the display backlight.