#include "quictestserver.h" #include #include #include #include #include #include #if defined(__MINGW32__) #ifndef _In_ #define _In_ #endif #ifndef _In_opt_ #define _In_opt_ #endif #ifndef _IRQL_requires_max_ #define _IRQL_requires_max_(level) #endif #ifndef _Pre_defensive_ #define _Pre_defensive_ #endif #ifndef _Out_writes_bytes_opt_ #define _Out_writes_bytes_opt_(size) #endif #ifndef _In_reads_or_z_opt_ #define _In_reads_or_z_opt_(size) #endif #ifndef _In_reads_ #define _In_reads_(size) #endif #ifndef _In_reads_bytes_ #define _In_reads_bytes_(size) #endif #ifndef _In_reads_bytes_opt_ #define _In_reads_bytes_opt_(size) #endif #ifndef _In_z_ #define _In_z_ #endif #ifndef _Inout_ #define _Inout_ #endif #ifndef _Out_ #define _Out_ #endif #ifndef _Out_writes_ #define _Out_writes_(size) #endif #ifndef _Outptr_ #define _Outptr_ #endif #ifndef _Success_ #define _Success_(condition) #endif #ifndef _In_range_ #define _In_range_(minimum, maximum) #endif #ifndef _Field_range_ #define _Field_range_(minimum, maximum) #endif #ifndef _Field_size_ #define _Field_size_(size) #endif #ifndef _Field_size_opt_ #define _Field_size_opt_(size) #endif #ifndef _Field_size_bytes_ #define _Field_size_bytes_(size) #endif #ifndef _Field_size_bytes_opt_ #define _Field_size_bytes_opt_(size) #endif #ifndef _Field_z_ #define _Field_z_ #endif #ifndef _Function_class_ #define _Function_class_(name) #endif #ifndef _When_ #define _When_(condition, annotation) #endif #ifndef _At_ #define _At_(target, annotation) #endif #ifndef _At_buffer_ #define _At_buffer_(target, iterator, bound, annotation) #endif #ifndef _Reserved_ #define _Reserved_ #endif #ifndef _Check_return_ #define _Check_return_ #endif #ifndef __drv_allocatesMem #define __drv_allocatesMem(kind) #endif #ifndef __drv_freesMem #define __drv_freesMem(kind) #endif #ifndef PASSIVE_LEVEL #define PASSIVE_LEVEL 0 #endif #ifndef DISPATCH_LEVEL #define DISPATCH_LEVEL 2 #endif #endif #include #include "cmvr/quic_edge/v1/quic_edge.pb.h" #include #include #include #include #include #include #include #include #include #include namespace { const quint32 kProtocolVersion = 1; const quint32 kMaximumControlFrameBytes = 1024U * 1024U; const QUIC_UINT62 kShutdownCode = 0x100U; const QUIC_UINT62 kProtocolErrorCode = 0x101U; QString tlsAlertName(quint8 alert) { switch (alert) { case 42: return QStringLiteral("bad_certificate"); case 43: return QStringLiteral("unsupported_certificate"); case 44: return QStringLiteral("certificate_revoked"); case 45: return QStringLiteral("certificate_expired"); case 46: return QStringLiteral("certificate_unknown"); case 48: return QStringLiteral("unknown_ca"); default: return QStringLiteral("unknown"); } } QString statusText(const char *operation, QUIC_STATUS status) { QString result = QStringLiteral("%1 失败,QUIC_STATUS=0x%2") .arg(QString::fromLatin1(operation)) .arg(static_cast(status), 0, 16); const quint32 rawStatus = static_cast(status); if ((rawStatus & 0xffffff00U) == 0x80410100U) { const quint8 alert = static_cast(rawStatus & 0xffU); result += QStringLiteral(",TLS alert %1 (%2)") .arg(alert) .arg(tlsAlertName(alert)); } return result; } QString addressText(const QUIC_ADDR *address) { if (!address) return QStringLiteral("--"); QUIC_ADDR_STR value = {}; if (!QuicAddrToString(address, &value)) return QStringLiteral("--"); return QString::fromLatin1(value.Address); } QString addressIpText(const QUIC_ADDR *address) { if (!address) return QStringLiteral("--"); char buffer[INET6_ADDRSTRLEN] = {}; if (address->si_family == AF_INET && InetNtopA(AF_INET, const_cast(&address->Ipv4.sin_addr), buffer, sizeof(buffer))) { return QString::fromLatin1(buffer); } if (address->si_family == AF_INET6 && InetNtopA(AF_INET6, const_cast(&address->Ipv6.sin6_addr), buffer, sizeof(buffer))) { return QString::fromLatin1(buffer); } return QStringLiteral("--"); } } class QuicTestServer::Impl { public: explicit Impl(QuicTestServer *owner) : m_owner(owner) { } ~Impl() { stop(); } bool isRunning() const { return m_running.load(); } quint16 boundPort() const { return m_boundPort.load(); } void start(const QString &bindAddress, quint16 port, const QString &alpn, const QString &pkcs12Path, const QString &password) { if (m_running.load()) { postLog(QStringLiteral("WARN"), QStringLiteral("QUIC Server 已经在运行")); return; } if (bindAddress.trimmed().isEmpty() || alpn.trimmed().isEmpty()) { postRunning(false, 0, QStringLiteral("监听地址和 ALPN 不能为空")); return; } m_registrations.store(0); m_heartbeats.store(0); m_datagrams.store(0); m_datagramBytes.store(0); postStatistics(); QFile certificateFile(pkcs12Path); if (!certificateFile.open(QIODevice::ReadOnly)) { postRunning(false, 0, QStringLiteral("无法读取测试证书:%1").arg(pkcs12Path)); return; } m_pkcs12 = certificateFile.readAll(); if (m_pkcs12.isEmpty()) { postRunning(false, 0, QStringLiteral("测试证书内容为空")); return; } const QString dllPath = QDir(QCoreApplication::applicationDirPath()) .filePath(QStringLiteral("msquic.dll")); m_library.setFileName(dllPath); if (!m_library.load()) { postRunning(false, 0, QStringLiteral("无法加载 %1:%2") .arg(dllPath, m_library.errorString())); return; } m_open = reinterpret_cast(m_library.resolve("MsQuicOpenVersion")); m_close = reinterpret_cast(m_library.resolve("MsQuicClose")); if (!m_open || !m_close) { failStart(QStringLiteral("msquic.dll 缺少 MsQuicOpenVersion/MsQuicClose")); return; } QUIC_STATUS status = m_open(QUIC_API_VERSION_2, reinterpret_cast(&m_api)); if (QUIC_FAILED(status)) { failStart(statusText("MsQuicOpenVersion", status)); return; } const QUIC_REGISTRATION_CONFIG registrationConfig = { "cmvr-qt-quic-test-server", QUIC_EXECUTION_PROFILE_LOW_LATENCY }; status = m_api->RegistrationOpen(®istrationConfig, &m_registration); if (QUIC_FAILED(status)) { failStart(statusText("RegistrationOpen", status)); return; } m_alpn = alpn.trimmed().toUtf8(); QUIC_BUFFER alpnBuffer = {}; alpnBuffer.Buffer = reinterpret_cast(m_alpn.data()); alpnBuffer.Length = static_cast(m_alpn.size()); QUIC_SETTINGS settings = {}; settings.IsSet.PeerBidiStreamCount = TRUE; settings.PeerBidiStreamCount = 1; settings.IsSet.PeerUnidiStreamCount = TRUE; settings.PeerUnidiStreamCount = 0; settings.IsSet.IdleTimeoutMs = TRUE; settings.IdleTimeoutMs = 120000; settings.IsSet.DatagramReceiveEnabled = TRUE; settings.DatagramReceiveEnabled = TRUE; status = m_api->ConfigurationOpen(m_registration, &alpnBuffer, 1, &settings, sizeof(settings), nullptr, &m_configuration); if (QUIC_FAILED(status)) { failStart(statusText("ConfigurationOpen", status)); return; } const QByteArray passwordBytes = password.toUtf8(); QUIC_CERTIFICATE_PKCS12 certificate = {}; certificate.Asn1Blob = reinterpret_cast(m_pkcs12.data()); certificate.Asn1BlobLength = static_cast(m_pkcs12.size()); certificate.PrivateKeyPassword = passwordBytes.constData(); QUIC_CREDENTIAL_CONFIG credential = {}; credential.Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_PKCS12; credential.Flags = QUIC_CREDENTIAL_FLAG_USE_PORTABLE_CERTIFICATES; credential.CertificatePkcs12 = &certificate; status = m_api->ConfigurationLoadCredential(m_configuration, &credential); if (QUIC_FAILED(status)) { failStart(statusText("ConfigurationLoadCredential", status)); return; } status = m_api->ListenerOpen(m_registration, &Impl::listenerCallback, this, &m_listener); if (QUIC_FAILED(status)) { failStart(statusText("ListenerOpen", status)); return; } QUIC_ADDR address = {}; const QByteArray bindBytes = bindAddress.trimmed().toLatin1(); if (!QuicAddrFromString(bindBytes.constData(), port, &address)) { failStart(QStringLiteral("QUIC 监听地址必须是数字 IPv4 或 IPv6 地址")); return; } status = m_api->ListenerStart(m_listener, &alpnBuffer, 1, &address); if (QUIC_FAILED(status)) { failStart(statusText("ListenerStart", status)); return; } QUIC_ADDR boundAddress = {}; uint32_t boundAddressSize = sizeof(boundAddress); status = m_api->GetParam(m_listener, QUIC_PARAM_LISTENER_LOCAL_ADDRESS, &boundAddressSize, &boundAddress); if (QUIC_FAILED(status)) { failStart(statusText("GetParam(LISTENER_LOCAL_ADDRESS)", status)); return; } m_bindAddress = bindAddress.trimmed(); m_boundPort.store(QuicAddrGetPort(&boundAddress)); m_running.store(true); m_stopping.store(false); postRunning(true, m_boundPort.load(), QStringLiteral("监听 %1,ALPN %2") .arg(addressText(&boundAddress), QString::fromUtf8(m_alpn))); postLog(QStringLiteral("INFO"), QStringLiteral("真实 QUIC/TLS 服务端已启动:%1").arg(addressText(&boundAddress))); } void stop() { if (!m_api && !m_library.isLoaded()) return; m_stopping.store(true); m_running.store(false); if (m_listener && m_api) { m_api->ListenerStop(m_listener); std::unique_lock lock(m_stateMutex); m_stateChanged.wait_for(lock, std::chrono::seconds(2), [this]() { return m_listenerStopped; }); lock.unlock(); m_api->ListenerClose(m_listener); m_listener = nullptr; } std::vector connections; { std::lock_guard lock(m_stateMutex); connections.assign(m_connections.begin(), m_connections.end()); } for (ConnectionContext *connection : connections) { if (connection && connection->handle) m_api->ConnectionShutdown(connection->handle, QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, kShutdownCode); } { std::unique_lock lock(m_stateMutex); m_stateChanged.wait_for(lock, std::chrono::seconds(3), [this]() { return m_liveContexts == 0; }); } if (m_configuration && m_api) { m_api->ConfigurationClose(m_configuration); m_configuration = nullptr; } if (m_registration && m_api) { m_api->RegistrationClose(m_registration); m_registration = nullptr; } if (m_api && m_close) { m_close(m_api); m_api = nullptr; } m_open = nullptr; m_close = nullptr; m_library.unload(); m_pkcs12.clear(); m_boundPort.store(0); m_listenerStopped = false; if (m_stopping.exchange(false)) { postRunning(false, 0, QStringLiteral("QUIC Server 已停止")); postLog(QStringLiteral("INFO"), QStringLiteral("QUIC Server 已停止")); } } private: struct SendContext { explicit SendContext(const QByteArray &value) : bytes(value) { buffer.Buffer = reinterpret_cast(bytes.data()); buffer.Length = static_cast(bytes.size()); } QByteArray bytes; QUIC_BUFFER buffer = {}; }; struct ConnectionContext { Impl *server = nullptr; HQUIC handle = nullptr; HQUIC stream = nullptr; QString peerAddress; QString peerIp; QByteArray receiveBuffer; QString nodeId; QString bootId; QString sessionId; quint64 lastInboundSequence = 0; quint64 nextOutboundSequence = 0; bool hasInboundSequence = false; bool receivedFirstMessage = false; bool registrationAttempted = false; bool registered = false; bool hasHeartbeatSequence = false; quint64 lastHeartbeatSequence = 0; std::atomic references{1}; std::mutex mutex; void addRef() { references.fetch_add(1); } void release() { if (references.fetch_sub(1) == 1) server->destroyContext(this); } }; void failStart(const QString &error) { postLog(QStringLiteral("ERROR"), error); postRunning(false, 0, error); stop(); } void destroyContext(ConnectionContext *context) { { std::lock_guard lock(m_stateMutex); if (m_liveContexts > 0) --m_liveContexts; } m_stateChanged.notify_all(); delete context; } void addConnection(ConnectionContext *context) { int count = 0; { std::lock_guard lock(m_stateMutex); m_connections.insert(context); ++m_liveContexts; count = static_cast(m_connections.size()); } postClientCount(count); postLog(QStringLiteral("INFO"), QStringLiteral("QUIC 客户端接入:%1").arg(context->peerAddress)); } void removeConnection(ConnectionContext *context) { int count = 0; { std::lock_guard lock(m_stateMutex); m_connections.erase(context); count = static_cast(m_connections.size()); } m_stateChanged.notify_all(); postClientCount(count); postLog(QStringLiteral("INFO"), QStringLiteral("QUIC 客户端断开:%1").arg(context->peerAddress)); } bool processFrame(ConnectionContext *context, const QByteArray &payload) { cmvr::quic_edge::v1::EdgeControlEnvelope envelope; if (!envelope.ParseFromArray(payload.constData(), payload.size())) { protocolViolation(context, QStringLiteral("控制消息 protobuf 解析失败"), 0); return false; } if (envelope.protocol_version() != kProtocolVersion) { protocolViolation(context, QStringLiteral("协议版本不是 1"), envelope.message_sequence()); return false; } if (context->hasInboundSequence && envelope.message_sequence() <= context->lastInboundSequence) { protocolViolation(context, QStringLiteral("message_sequence 未严格递增"), envelope.message_sequence()); return false; } context->hasInboundSequence = true; context->lastInboundSequence = envelope.message_sequence(); if (!context->receivedFirstMessage && !envelope.has_node_register_request()) { protocolViolation(context, QStringLiteral("NodeRegisterRequest 必须是首条控制消息"), envelope.message_sequence()); return false; } context->receivedFirstMessage = true; if (envelope.has_node_register_request()) return handleRegistration(context, envelope.node_register_request()); if (envelope.has_node_heartbeat()) return handleHeartbeat(context, envelope.node_heartbeat()); if (envelope.has_media_session_open()) { postLog(QStringLiteral("INFO"), QStringLiteral("媒体会话已打开:epoch=%1") .arg(envelope.media_session_open().session_epoch())); return true; } if (envelope.has_media_track_descriptor()) { const auto &descriptor = envelope.media_track_descriptor(); postLog(QStringLiteral("INFO"), QStringLiteral("媒体轨道:ID=%1,设备=%2,编码=%3") .arg(descriptor.track_id()) .arg(QString::fromStdString(descriptor.device_id()), QString::fromStdString(descriptor.codec()))); return true; } postLog(QStringLiteral("WARN"), QStringLiteral("收到未处理的 QUIC 控制消息")); return true; } bool handleRegistration(ConnectionContext *context, const cmvr::quic_edge::v1::NodeRegisterRequest &request) { const auto &node = request.node(); if (context->registrationAttempted || context->registered || node.node_id().empty() || node.boot_id().empty()) { protocolViolation(context, QStringLiteral("节点注册无效或重复"), context->lastInboundSequence); return false; } context->registrationAttempted = true; context->nodeId = QString::fromStdString(node.node_id()); context->bootId = QString::fromStdString(node.boot_id()); context->sessionId = QStringLiteral("qt-%1-%2") .arg(QDateTime::currentMSecsSinceEpoch()) .arg(m_nextSession.fetch_add(1)); context->registered = true; m_registrations.fetch_add(1); cmvr::quic_edge::v1::EdgeControlEnvelope response; response.set_protocol_version(kProtocolVersion); response.set_message_sequence(context->nextOutboundSequence++); auto *registration = response.mutable_node_register_response(); registration->set_accepted(true); registration->set_session_id(context->sessionId.toStdString()); registration->set_message("accepted by CMVR Qt QUIC test server"); registration->set_heartbeat_interval_ms(1000); registration->set_observed_source_ip(context->peerIp.toStdString()); if (!sendEnvelope(context, response)) return false; const QString grpcEndpoint = QStringLiteral("%1:%2%3") .arg(QString::fromStdString(node.grpc_endpoint().host())) .arg(node.grpc_endpoint().port()) .arg(node.grpc_endpoint().tls() ? QStringLiteral(" TLS") : QString()); postNode(context->nodeId, context->bootId, grpcEndpoint, context->peerAddress); postLog(QStringLiteral("OK"), QStringLiteral("节点注册成功:%1,session=%2") .arg(context->nodeId, context->sessionId)); postStatistics(); return true; } bool handleHeartbeat(ConnectionContext *context, const cmvr::quic_edge::v1::NodeHeartbeat &heartbeat) { if (!context->registered || QString::fromStdString(heartbeat.session_id()) != context->sessionId || QString::fromStdString(heartbeat.node_id()) != context->nodeId || QString::fromStdString(heartbeat.boot_id()) != context->bootId || (context->hasHeartbeatSequence && heartbeat.sequence() <= context->lastHeartbeatSequence)) { protocolViolation(context, QStringLiteral("心跳 session 与注册会话不一致"), context->lastInboundSequence); return false; } context->hasHeartbeatSequence = true; context->lastHeartbeatSequence = heartbeat.sequence(); m_heartbeats.fetch_add(1); cmvr::quic_edge::v1::EdgeControlEnvelope response; response.set_protocol_version(kProtocolVersion); response.set_message_sequence(context->nextOutboundSequence++); auto *ack = response.mutable_node_heartbeat_ack(); ack->set_accepted(true); ack->set_acknowledged_sequence(heartbeat.sequence()); ack->set_message("ok"); ack->set_server_time_unix_ms(QDateTime::currentMSecsSinceEpoch()); ack->set_observed_source_ip(context->peerIp.toStdString()); ack->set_session_id(context->sessionId.toStdString()); if (!sendEnvelope(context, response)) return false; postLog(QStringLiteral("INFO"), QStringLiteral("心跳 #%1,节点 %2,设备 %3") .arg(heartbeat.sequence()) .arg(context->nodeId) .arg(heartbeat.has_device_manager() ? heartbeat.device_manager().devices_size() : 0)); postStatistics(); return true; } bool sendEnvelope(ConnectionContext *context, const cmvr::quic_edge::v1::EdgeControlEnvelope &envelope) { std::string payload; if (!envelope.SerializeToString(&payload) || payload.size() > kMaximumControlFrameBytes) return false; QByteArray frame; frame.resize(static_cast(payload.size()) + 4); const quint32 size = static_cast(payload.size()); frame[0] = static_cast((size >> 24) & 0xff); frame[1] = static_cast((size >> 16) & 0xff); frame[2] = static_cast((size >> 8) & 0xff); frame[3] = static_cast(size & 0xff); if (!payload.empty()) std::memcpy(frame.data() + 4, payload.data(), payload.size()); SendContext *send = new SendContext(frame); QUIC_STATUS status = QUIC_STATUS_INVALID_PARAMETER; { std::lock_guard lock(context->mutex); if (context->stream) status = m_api->StreamSend(context->stream, &send->buffer, 1, QUIC_SEND_FLAG_NONE, send); } if (QUIC_FAILED(status)) { delete send; postLog(QStringLiteral("ERROR"), statusText("StreamSend", status)); return false; } return true; } void protocolViolation(ConnectionContext *context, const QString &message, quint64 relatedSequence) { postLog(QStringLiteral("ERROR"), QStringLiteral("QUIC 协议错误:%1").arg(message)); if (context->stream) { cmvr::quic_edge::v1::EdgeControlEnvelope response; response.set_protocol_version(kProtocolVersion); response.set_message_sequence(context->nextOutboundSequence++); auto *error = response.mutable_protocol_error(); error->set_code(1); error->set_message(message.toStdString()); error->set_related_message_sequence(relatedSequence); error->set_fatal(true); sendEnvelope(context, response); } if (context->handle) m_api->ConnectionShutdown(context->handle, QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, kProtocolErrorCode); } QUIC_STATUS onStreamReceive(ConnectionContext *context, QUIC_STREAM_EVENT *event) { quint64 total = 0; std::vector payloads; bool frameTooLarge = false; for (uint32_t index = 0; index < event->RECEIVE.BufferCount; ++index) total += event->RECEIVE.Buffers[index].Length; if (total > kMaximumControlFrameBytes + 4U) return QUIC_STATUS_BUFFER_TOO_SMALL; { std::lock_guard lock(context->mutex); for (uint32_t index = 0; index < event->RECEIVE.BufferCount; ++index) { const QUIC_BUFFER &buffer = event->RECEIVE.Buffers[index]; context->receiveBuffer.append(reinterpret_cast(buffer.Buffer), static_cast(buffer.Length)); } while (context->receiveBuffer.size() >= 4) { const unsigned char *data = reinterpret_cast( context->receiveBuffer.constData()); const quint32 size = (static_cast(data[0]) << 24) | (static_cast(data[1]) << 16) | (static_cast(data[2]) << 8) | static_cast(data[3]); if (size > kMaximumControlFrameBytes) { frameTooLarge = true; break; } if (context->receiveBuffer.size() < static_cast(size + 4U)) break; payloads.push_back(context->receiveBuffer.mid(4, static_cast(size))); context->receiveBuffer.remove(0, static_cast(size + 4U)); } } if (frameTooLarge) { protocolViolation(context, QStringLiteral("控制帧超过 1 MiB"), 0); return QUIC_STATUS_BUFFER_TOO_SMALL; } for (const QByteArray &payload : payloads) { if (!processFrame(context, payload)) break; } return QUIC_STATUS_SUCCESS; } static QUIC_STATUS QUIC_API listenerCallback(HQUIC, void *context, QUIC_LISTENER_EVENT *event) { Impl *server = static_cast(context); if (!server || !event) return QUIC_STATUS_INVALID_PARAMETER; if (event->Type == QUIC_LISTENER_EVENT_STOP_COMPLETE) { { std::lock_guard lock(server->m_stateMutex); server->m_listenerStopped = true; } server->m_stateChanged.notify_all(); return QUIC_STATUS_SUCCESS; } if (event->Type != QUIC_LISTENER_EVENT_NEW_CONNECTION || server->m_stopping.load()) return QUIC_STATUS_SUCCESS; ConnectionContext *connection = new ConnectionContext; connection->server = server; connection->handle = event->NEW_CONNECTION.Connection; connection->peerAddress = event->NEW_CONNECTION.Info ? addressText(event->NEW_CONNECTION.Info->RemoteAddress) : QStringLiteral("--"); connection->peerIp = event->NEW_CONNECTION.Info ? addressIpText(event->NEW_CONNECTION.Info->RemoteAddress) : QStringLiteral("--"); server->m_api->SetCallbackHandler(connection->handle, reinterpret_cast(&Impl::connectionCallback), connection); server->addConnection(connection); const QUIC_STATUS status = server->m_api->ConnectionSetConfiguration( connection->handle, server->m_configuration); if (QUIC_FAILED(status)) { server->m_api->ConnectionClose(connection->handle); connection->handle = nullptr; server->removeConnection(connection); connection->release(); } return status; } static QUIC_STATUS QUIC_API connectionCallback(HQUIC handle, void *context, QUIC_CONNECTION_EVENT *event) { ConnectionContext *connection = static_cast(context); if (!connection || !event) return QUIC_STATUS_INVALID_PARAMETER; Impl *server = connection->server; switch (event->Type) { case QUIC_CONNECTION_EVENT_CONNECTED: server->postLog(QStringLiteral("OK"), QStringLiteral("QUIC/TLS 握手完成:%1").arg(connection->peerAddress)); break; case QUIC_CONNECTION_EVENT_PEER_STREAM_STARTED: if ((event->PEER_STREAM_STARTED.Flags & QUIC_STREAM_OPEN_FLAG_UNIDIRECTIONAL) || connection->stream) { server->m_api->StreamClose(event->PEER_STREAM_STARTED.Stream); server->m_api->ConnectionShutdown(handle, QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, kProtocolErrorCode); break; } { std::lock_guard lock(connection->mutex); connection->stream = event->PEER_STREAM_STARTED.Stream; connection->addRef(); } server->m_api->SetCallbackHandler(connection->stream, reinterpret_cast(&Impl::streamCallback), connection); server->postLog(QStringLiteral("INFO"), QStringLiteral("可靠控制流已建立")); break; case QUIC_CONNECTION_EVENT_DATAGRAM_RECEIVED: if (event->DATAGRAM_RECEIVED.Buffer) { server->m_datagrams.fetch_add(1); server->m_datagramBytes.fetch_add(event->DATAGRAM_RECEIVED.Buffer->Length); server->postStatistics(); } break; case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT: server->postLog(QStringLiteral("WARN"), statusText("QUIC transport", event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status)); break; case QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE: connection->handle = nullptr; server->m_api->ConnectionClose(handle); server->removeConnection(connection); connection->release(); break; default: break; } return QUIC_STATUS_SUCCESS; } static QUIC_STATUS QUIC_API streamCallback(HQUIC stream, void *context, QUIC_STREAM_EVENT *event) { ConnectionContext *connection = static_cast(context); if (!connection || !event) return QUIC_STATUS_INVALID_PARAMETER; Impl *server = connection->server; switch (event->Type) { case QUIC_STREAM_EVENT_RECEIVE: return server->onStreamReceive(connection, event); case QUIC_STREAM_EVENT_SEND_COMPLETE: delete static_cast(event->SEND_COMPLETE.ClientContext); break; case QUIC_STREAM_EVENT_PEER_SEND_SHUTDOWN: server->m_api->StreamShutdown(stream, QUIC_STREAM_SHUTDOWN_FLAG_GRACEFUL, 0); break; case QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE: { std::lock_guard lock(connection->mutex); if (connection->stream == stream) connection->stream = nullptr; } server->m_api->StreamClose(stream); connection->release(); break; default: break; } return QUIC_STATUS_SUCCESS; } void postRunning(bool running, quint16 port, const QString &detail) { QMetaObject::invokeMethod(m_owner, [this, running, port, detail]() { emit m_owner->runningChanged(running, port, detail); }, Qt::QueuedConnection); } void postClientCount(int count) { QMetaObject::invokeMethod(m_owner, [this, count]() { emit m_owner->clientCountChanged(count); }, Qt::QueuedConnection); } void postStatistics() { const quint64 registrations = m_registrations.load(); const quint64 heartbeats = m_heartbeats.load(); const quint64 datagrams = m_datagrams.load(); const quint64 bytes = m_datagramBytes.load(); QMetaObject::invokeMethod(m_owner, [this, registrations, heartbeats, datagrams, bytes]() { emit m_owner->statisticsChanged(registrations, heartbeats, datagrams, bytes); }, Qt::QueuedConnection); } void postNode(const QString &nodeId, const QString &bootId, const QString &grpcEndpoint, const QString &peerAddress) { QMetaObject::invokeMethod(m_owner, [this, nodeId, bootId, grpcEndpoint, peerAddress]() { emit m_owner->nodeRegistered(nodeId, bootId, grpcEndpoint, peerAddress); }, Qt::QueuedConnection); } void postLog(const QString &level, const QString &message) { QMetaObject::invokeMethod(m_owner, [this, level, message]() { emit m_owner->logMessage(level, message); }, Qt::QueuedConnection); } QuicTestServer *m_owner = nullptr; QLibrary m_library; MsQuicOpenVersionFn m_open = nullptr; MsQuicCloseFn m_close = nullptr; const QUIC_API_TABLE *m_api = nullptr; HQUIC m_registration = nullptr; HQUIC m_configuration = nullptr; HQUIC m_listener = nullptr; QByteArray m_alpn; QByteArray m_pkcs12; QString m_bindAddress; std::atomic m_running{false}; std::atomic m_stopping{false}; std::atomic m_boundPort{0}; std::atomic m_registrations{0}; std::atomic m_heartbeats{0}; std::atomic m_datagrams{0}; std::atomic m_datagramBytes{0}; std::atomic m_nextSession{1}; std::mutex m_stateMutex; std::condition_variable m_stateChanged; std::set m_connections; int m_liveContexts = 0; bool m_listenerStopped = false; }; QuicTestServer::QuicTestServer(QObject *parent) : QObject(parent), m_impl(new Impl(this)) { } QuicTestServer::~QuicTestServer() = default; bool QuicTestServer::isRunning() const { return m_impl->isRunning(); } quint16 QuicTestServer::boundPort() const { return m_impl->boundPort(); } void QuicTestServer::startServer(const QString &bindAddress, quint16 port, const QString &alpn, const QString &pkcs12Path, const QString &password) { m_impl->start(bindAddress, port, alpn, pkcs12Path, password); } void QuicTestServer::stopServer() { m_impl->stop(); }