added QUIC
This commit is contained in:
parent
de2073422c
commit
45479a46ff
22 changed files with 1448 additions and 66 deletions
172
interfaces/Crafter.Network-ClientQUIC.cppm
Normal file
172
interfaces/Crafter.Network-ClientQUIC.cppm
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
Crafter®.Network
|
||||
Copyright (C) 2026 Catcrafts®
|
||||
Catcrafts.net
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3.0 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
module;
|
||||
#include <msquic.h>
|
||||
export module Crafter.Network:ClientQUIC;
|
||||
import std;
|
||||
|
||||
namespace Crafter {
|
||||
export class ListenerQUIC;
|
||||
|
||||
export class QUICException : public std::runtime_error {
|
||||
public:
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
export class QUICClosedException : public std::exception {
|
||||
public:
|
||||
const char* what() const noexcept override { return "QUIC connection closed"; }
|
||||
};
|
||||
|
||||
// Server certificate sources. Pick one of (filePaths) or (selfSigned).
|
||||
// selfSigned generates an in-memory ephemeral cert — fine for dev/LAN.
|
||||
export struct QUICServerCredentials {
|
||||
std::string certPath;
|
||||
std::string keyPath;
|
||||
bool selfSigned = false;
|
||||
};
|
||||
|
||||
// Client-side credential validation. By default we require a real cert.
|
||||
// insecureNoServerValidation disables peer cert checks — only for dev.
|
||||
export struct QUICClientCredentials {
|
||||
bool insecureNoServerValidation = false;
|
||||
};
|
||||
|
||||
export class ClientQUIC;
|
||||
|
||||
// A reliable, ordered, bidirectional stream within a QUIC connection.
|
||||
// Owned by ClientQUIC; do not destroy directly. Obtain via
|
||||
// ClientQUIC::OpenStream() or via the on-stream callback for inbound
|
||||
// streams initiated by the peer.
|
||||
export class QUICStream {
|
||||
public:
|
||||
// Underlying msquic HQUIC handle. Treated as opaque by callers.
|
||||
HQUIC handle = nullptr;
|
||||
|
||||
// The connection that owns this stream (non-owning).
|
||||
ClientQUIC* connection = nullptr;
|
||||
|
||||
QUICStream() = default;
|
||||
QUICStream(HQUIC handle, ClientQUIC* connection);
|
||||
~QUICStream();
|
||||
QUICStream(const QUICStream&) = delete;
|
||||
QUICStream(QUICStream&&) noexcept;
|
||||
QUICStream& operator=(QUICStream&&) noexcept;
|
||||
|
||||
// Send a buffer. If finish=true, the send-side of the stream is closed
|
||||
// after the buffer is delivered (peer will see graceful shutdown).
|
||||
// Blocks until msquic accepts the buffer; throws on stream/conn close.
|
||||
void SendSync(const void* buffer, std::uint32_t size, bool finish = false);
|
||||
|
||||
// Block until at least one byte is received; returns the received
|
||||
// chunk. Throws QUICClosedException once the peer has closed the
|
||||
// send-side and the buffer is drained.
|
||||
std::vector<char> RecieveSync();
|
||||
|
||||
// Read until the peer closes the send-side, accumulating all chunks.
|
||||
std::vector<char> RecieveUntilCloseSync();
|
||||
|
||||
// Read exactly bufferSize bytes; throws if the peer closes early.
|
||||
std::vector<char> RecieveUntilFullSync(std::uint32_t bufferSize);
|
||||
|
||||
// Async variants: dispatched on Crafter.Thread's ThreadPool.
|
||||
void RecieveAsync(std::function<void(std::vector<char>)> recieveCallback);
|
||||
void RecieveUntilCloseAsync(std::function<void(std::vector<char>)> recieveCallback);
|
||||
void RecieveUntilFullAsync(std::uint32_t bufferSize, std::function<void(std::vector<char>)> recieveCallback);
|
||||
|
||||
// Cleanly shut down the stream (both directions).
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
friend class ClientQUIC;
|
||||
};
|
||||
|
||||
// A QUIC connection. On the client side, constructing one initiates the
|
||||
// handshake and blocks until it succeeds (or throws on failure). On the
|
||||
// server side, ListenerQUIC instantiates these for accepted peers.
|
||||
//
|
||||
// A connection multiplexes:
|
||||
// - Reliable, ordered streams (open via OpenStream() / observe inbound
|
||||
// via OnStream()).
|
||||
// - Unreliable, unordered datagrams (SendDatagram() / OnDatagram()).
|
||||
//
|
||||
// Lifetime: ~ClientQUIC closes the connection. Streams obtained from
|
||||
// OpenStream() are scoped to the connection and must be destroyed (or
|
||||
// moved out) before the ClientQUIC.
|
||||
export class ClientQUIC {
|
||||
public:
|
||||
// ALPN identifier exchanged in the handshake. Both peers must agree.
|
||||
// For 3DForts use e.g. "f3d/1" or similar — a short stable token.
|
||||
std::string alpn;
|
||||
|
||||
// Client constructor: connects to host:port using QUIC. ALPN must
|
||||
// match the listener. Throws QUICException on connect failure.
|
||||
ClientQUIC(const char* host, std::uint16_t port, std::string alpn,
|
||||
QUICClientCredentials creds = {});
|
||||
ClientQUIC(std::string host, std::uint16_t port, std::string alpn,
|
||||
QUICClientCredentials creds = {});
|
||||
|
||||
// Server-side constructor used by ListenerQUIC for accepted peers.
|
||||
// Takes ownership of an already-accepted msquic connection handle
|
||||
// and the server configuration handle. Not intended for direct use.
|
||||
ClientQUIC(HQUIC connectionHandle, HQUIC serverConfiguration, std::string alpn);
|
||||
|
||||
~ClientQUIC();
|
||||
ClientQUIC(const ClientQUIC&) = delete;
|
||||
ClientQUIC(ClientQUIC&&) noexcept;
|
||||
|
||||
// Open a new bidirectional stream initiated by this side.
|
||||
// Blocks until the stream is started; throws on failure.
|
||||
QUICStream OpenStream();
|
||||
|
||||
// Send a datagram. Best-effort: may be silently dropped under loss
|
||||
// or congestion. Size must fit within the path MTU (msquic surfaces
|
||||
// the maximum via QUIC_PARAM_CONN_DATAGRAM_SEND_ENABLED — typically
|
||||
// ~1200 bytes safely on the open internet).
|
||||
void SendDatagram(const void* buffer, std::uint32_t size);
|
||||
|
||||
// Register a handler for streams the peer initiates toward us.
|
||||
// Called on the msquic worker; offload heavy work to ThreadPool.
|
||||
void OnStream(std::function<void(QUICStream)> callback);
|
||||
|
||||
// Register a handler for datagrams from the peer. Called on the
|
||||
// msquic worker; copy/queue and return promptly.
|
||||
void OnDatagram(std::function<void(std::vector<char>)> callback);
|
||||
|
||||
// Block the caller until the next datagram arrives; returns it.
|
||||
// Throws QUICClosedException if the connection closes first.
|
||||
std::vector<char> RecieveDatagramSync();
|
||||
|
||||
// Cleanly shut down the connection.
|
||||
void Stop();
|
||||
|
||||
// Underlying handle for advanced use (parameter queries, etc.).
|
||||
HQUIC GetHandle() const;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
friend class ListenerQUIC;
|
||||
friend class QUICStream;
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue