* UDP enclave echo server
This is an end-to-end UDP echo server, which receives UDP packets from
multiple clients at the same time, passes them to the enclave with a
message type that is handled by a QUICEchoEndpoint (which just echoes
back the messages to the client) and send the message back through the
ring buffer to the host, which then send to the correct client.
The UDP packets, alongside their socket addresses, are passed to the
enclave as quic_inbound rung buffer messages and received back as
quic_outbound messages. For now, those are encoded as {long,long} to
avoid size issues in the serialization, but eventually, they'll be
broken down to their components {short,char[14]}.
UDP interfaces are created like their TCP counterparts, via a new
field in RPCInterface called 'protocol', with default to "tcp". If
the field is set to "udp", the host will listen on the UDP version
of RPCConnection and use the 'quic_*' messages, which connects to the
new QUICEchoEndpoint.
Also:
* Renaming "service" to "port"
* Refactoring TCPBehaviour into SocketBehaviour<ConnType>
* Factor next_id out to share amongst all RPC connections
* Use local ConnID in rpc_connections, same as tcp/udp
* Factor some common logic into socket.h
* Factor pending writes/reads into ds/pending_io.h
Issues:
* There is an implicit 'quic_start' message but not a 'quic_close' one,
which can be a problem for many connections, over time. It's not
clear to me yet that this will create leaks / mismatches, but we have
to make sure it doesn't on the next step.
* The current RPCConnections is parametrized by TCPImpl/UDPImpl, which
is handy for now but creates the implicit structural dependency
between the two parameters. We need a common interface to derive
from, so that the two structures can actually be checked at compile
time.
* To implement the step above, we need to fix 'proxy_ptr' and
'close_ptr' to allow pointer checks (virtual inheritance). I tried
implementing that first but it creates ripples throughout the code.
We may never fix this, but then things like the auto-increment will
have to continue being external, amongst other things.
Next Steps:
1. To implement all services through unencrypted UDP, just like TCP, so
we can test the longecity and stability of the UDP channel. We can
ignore all TLS errors, and just make sure requests and responses are
passed to the right services and back to the right clients. This
will also need a UDP client, so that nodes can RPC each other in
UDP.
2. To implement QUICEndpoint using ngtcp2 and HTTP3Endpoint using nghttp3
and test using proper TLS certificates and make sure the services are
still available in the same way.
* Unnecessary uv dependency in quic_endpoint
* Increasing number of doxygen graph nodes
* Simplify UDP echo test
* Remove unnecessary FIXME workaround
* if constexpr isTCP/isUDP
* Fix sockaddr encoding to {short,char[14]}
* Testing multiple UDP messages