| /** @file |
| * |
| * A brief file description |
| * |
| * @section license License |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include "P_Net.h" |
| |
| #include "QUICApplication.h" |
| #include "QUICStreamManager.h" |
| #include "QUICLossDetector.h" |
| #include "QUICEvents.h" |
| |
| class MockQUICContext; |
| |
| using namespace std::literals; |
| std::string_view negotiated_application_name_sv = "h3-23"sv; |
| |
| class MockQUICLDConfig : public QUICLDConfig |
| { |
| uint32_t |
| packet_threshold() const |
| { |
| return 3; |
| } |
| |
| float |
| time_threshold() const |
| { |
| return 1.25; |
| } |
| |
| ink_hrtime |
| granularity() const |
| { |
| return HRTIME_MSECONDS(1); |
| } |
| |
| ink_hrtime |
| initial_rtt() const |
| { |
| return HRTIME_MSECONDS(100); |
| } |
| }; |
| |
| class MockQUICCCConfig : public QUICCCConfig |
| { |
| uint32_t |
| max_datagram_size() const |
| { |
| return 1200; |
| } |
| |
| uint32_t |
| initial_window() const |
| { |
| return 10; |
| } |
| |
| uint32_t |
| minimum_window() const |
| { |
| return 2; |
| } |
| |
| float |
| loss_reduction_factor() const |
| { |
| return 0.5; |
| } |
| |
| uint32_t |
| persistent_congestion_threshold() const |
| { |
| return 2; |
| } |
| }; |
| |
| class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider |
| { |
| QUICConnectionId |
| connection_id() const override |
| { |
| return {reinterpret_cast<const uint8_t *>("\x00"), 1}; |
| } |
| |
| QUICConnectionId |
| peer_connection_id() const override |
| { |
| return {reinterpret_cast<const uint8_t *>("\x00"), 1}; |
| } |
| |
| QUICConnectionId |
| original_connection_id() const override |
| { |
| return {reinterpret_cast<const uint8_t *>("\x00"), 1}; |
| } |
| |
| QUICConnectionId |
| first_connection_id() const override |
| { |
| return {reinterpret_cast<const uint8_t *>("\x00"), 1}; |
| } |
| |
| const QUICFiveTuple |
| five_tuple() const override |
| { |
| return QUICFiveTuple(); |
| } |
| |
| std::string_view |
| cids() const override |
| { |
| using namespace std::literals; |
| return std::string_view("00000000-00000000"sv); |
| } |
| |
| uint32_t |
| pmtu() const override |
| { |
| return 1280; |
| } |
| |
| NetVConnectionContext_t |
| direction() const override |
| { |
| return NET_VCONNECTION_OUT; |
| } |
| |
| int |
| select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, |
| unsigned inlen) const override |
| { |
| return SSL_TLSEXT_ERR_OK; |
| } |
| |
| bool |
| is_closed() const override |
| { |
| return false; |
| } |
| |
| std::string_view |
| negotiated_application_name() const override |
| { |
| return negotiated_application_name_sv; |
| } |
| }; |
| |
| class MockQUICStreamManager : public QUICStreamManager |
| { |
| public: |
| MockQUICStreamManager(QUICConnectionInfoProvider *info) : QUICStreamManager(info, nullptr, nullptr) {} |
| |
| // Override |
| virtual QUICConnectionErrorUPtr |
| handle_frame(QUICEncryptionLevel level, const QUICFrame &f) override |
| { |
| ++_frameCount[static_cast<int>(f.type())]; |
| ++_totalFrameCount; |
| |
| return nullptr; |
| } |
| |
| // for Test |
| int |
| getStreamFrameCount() |
| { |
| return _frameCount[static_cast<int>(QUICFrameType::STREAM)]; |
| } |
| |
| int |
| getAckFrameCount() |
| { |
| return _frameCount[static_cast<int>(QUICFrameType::ACK)]; |
| } |
| |
| int |
| getPingFrameCount() |
| { |
| return _frameCount[static_cast<int>(QUICFrameType::PING)]; |
| } |
| |
| int |
| getTotalFrameCount() |
| { |
| return _totalFrameCount; |
| } |
| |
| private: |
| int _totalFrameCount = 0; |
| int _frameCount[256] = {0}; |
| }; |
| |
| class MockNetVConnection : public NetVConnection |
| { |
| public: |
| MockNetVConnection(NetVConnectionContext_t context = NET_VCONNECTION_OUT) : NetVConnection() { netvc_context = context; } |
| VIO * |
| do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) |
| { |
| return nullptr; |
| }; |
| VIO * |
| do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) |
| { |
| return nullptr; |
| }; |
| void do_io_close(int lerrno = -1){}; |
| void do_io_shutdown(ShutdownHowTo_t howto){}; |
| void reenable(VIO *vio){}; |
| void reenable_re(VIO *vio){}; |
| void set_active_timeout(ink_hrtime timeout_in){}; |
| void set_inactivity_timeout(ink_hrtime timeout_in){}; |
| void cancel_active_timeout(){}; |
| void cancel_inactivity_timeout(){}; |
| void add_to_keep_alive_queue(){}; |
| void remove_from_keep_alive_queue(){}; |
| bool |
| add_to_active_queue() |
| { |
| return true; |
| }; |
| ink_hrtime |
| get_active_timeout() |
| { |
| return 0; |
| } |
| ink_hrtime |
| get_inactivity_timeout() |
| { |
| return 0; |
| } |
| void |
| apply_options() |
| { |
| } |
| SOCKET |
| get_socket() { return 0; } |
| int |
| set_tcp_init_cwnd(int init_cwnd) |
| { |
| return 0; |
| } |
| int |
| set_tcp_congestion_control(int side) |
| { |
| return 0; |
| } |
| void set_local_addr(){}; |
| void set_remote_addr(){}; |
| |
| NetVConnectionContext_t |
| get_context() const |
| { |
| return netvc_context; |
| } |
| }; |
| |
| class MockQUICConnection : public QUICConnection |
| { |
| public: |
| MockQUICConnection(NetVConnectionContext_t context = NET_VCONNECTION_OUT) : QUICConnection(), _direction(context) |
| { |
| this->_mutex = new_ProxyMutex(); |
| }; |
| |
| QUICConnectionId |
| connection_id() const override |
| { |
| return {reinterpret_cast<const uint8_t *>("\x00"), 1}; |
| } |
| |
| QUICConnectionId |
| peer_connection_id() const override |
| { |
| return {reinterpret_cast<const uint8_t *>("\x00"), 1}; |
| } |
| |
| QUICConnectionId |
| original_connection_id() const override |
| { |
| return {reinterpret_cast<const uint8_t *>("\x00"), 1}; |
| } |
| |
| QUICConnectionId |
| first_connection_id() const override |
| { |
| return {reinterpret_cast<const uint8_t *>("\x00"), 1}; |
| } |
| |
| const QUICFiveTuple |
| five_tuple() const override |
| { |
| return QUICFiveTuple(); |
| } |
| |
| std::string_view |
| cids() const override |
| { |
| using namespace std::literals; |
| return std::string_view("00000000-00000000"sv); |
| } |
| |
| std::vector<QUICFrameType> |
| interests() override |
| { |
| return {QUICFrameType::CONNECTION_CLOSE}; |
| } |
| |
| QUICConnectionErrorUPtr |
| handle_frame(QUICEncryptionLevel level, const QUICFrame &f) override |
| { |
| ++_frameCount[static_cast<int>(f.type())]; |
| ++_totalFrameCount; |
| |
| return nullptr; |
| } |
| |
| uint32_t |
| pmtu() const override |
| { |
| return 1280; |
| } |
| |
| NetVConnectionContext_t |
| direction() const override |
| { |
| return _direction; |
| } |
| |
| void |
| close(QUICConnectionErrorUPtr error) override |
| { |
| } |
| |
| int |
| getTotalFrameCount() |
| { |
| return _totalFrameCount; |
| } |
| |
| QUICStreamManager * |
| stream_manager() override |
| { |
| return &_stream_manager; |
| } |
| |
| bool |
| is_closed() const override |
| { |
| return false; |
| } |
| |
| void |
| handle_received_packet(UDPPacket *) override |
| { |
| } |
| |
| void |
| ping() override |
| { |
| } |
| |
| std::string_view |
| negotiated_application_name() const override |
| { |
| return negotiated_application_name_sv; |
| } |
| |
| int |
| select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, |
| unsigned inlen) const override |
| { |
| return SSL_TLSEXT_ERR_OK; |
| } |
| |
| int _transmit_count = 0; |
| int _retransmit_count = 0; |
| Ptr<ProxyMutex> _mutex; |
| int _totalFrameCount = 0; |
| int _frameCount[256] = {0}; |
| MockQUICStreamManager _stream_manager = {this}; |
| |
| QUICTransportParametersInEncryptedExtensions dummy_transport_parameters(); |
| NetVConnectionContext_t _direction; |
| }; |
| |
| class MockQUICCongestionController : public QUICCongestionController |
| { |
| public: |
| MockQUICCongestionController() {} |
| // Override |
| virtual void |
| on_packets_lost(const std::map<QUICPacketNumber, QUICPacketInfo *> &packets) override |
| { |
| for (auto &p : packets) { |
| lost_packets.insert(p.first); |
| } |
| } |
| |
| virtual void |
| on_packet_sent(size_t bytes_sent) override |
| { |
| } |
| virtual void |
| on_packet_acked(const QUICPacketInfo &acked_packet) override |
| { |
| } |
| virtual void |
| process_ecn(const QUICPacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section) override |
| { |
| } |
| virtual void |
| add_extra_credit() override |
| { |
| } |
| virtual void |
| reset() override |
| { |
| } |
| virtual uint32_t |
| credit() const override |
| { |
| return 0; |
| } |
| |
| // for Test |
| int |
| getStreamFrameCount() |
| { |
| return _frameCount[static_cast<int>(QUICFrameType::STREAM)]; |
| } |
| |
| int |
| getAckFrameCount() |
| { |
| return _frameCount[static_cast<int>(QUICFrameType::ACK)]; |
| } |
| |
| int |
| getPingFrameCount() |
| { |
| return _frameCount[static_cast<int>(QUICFrameType::PING)]; |
| } |
| |
| int |
| getTotalFrameCount() |
| { |
| return _totalFrameCount; |
| } |
| |
| std::set<QUICPacketNumber> lost_packets; |
| |
| private: |
| int _totalFrameCount = 0; |
| int _frameCount[256] = {0}; |
| }; |
| |
| class MockQUICPacketProtectionKeyInfo : public QUICPacketProtectionKeyInfo |
| { |
| public: |
| const EVP_CIPHER * |
| get_cipher(QUICKeyPhase phase) const override |
| { |
| return EVP_aes_128_gcm(); |
| } |
| |
| size_t |
| get_tag_len(QUICKeyPhase phase) const override |
| { |
| return EVP_GCM_TLS_TAG_LEN; |
| } |
| |
| const size_t *encryption_iv_len(QUICKeyPhase) const override |
| { |
| static size_t dummy = 12; |
| return &dummy; |
| } |
| }; |
| |
| class MockQUICContext : public QUICContext, public QUICLDContext, public QUICCCContext |
| { |
| public: |
| MockQUICContext() |
| { |
| _info = std::make_unique<MockQUICConnectionInfoProvider>(); |
| _key_info = std::make_unique<MockQUICPacketProtectionKeyInfo>(); |
| _ld_config = std::make_unique<MockQUICLDConfig>(); |
| _cc_config = std::make_unique<MockQUICCCConfig>(); |
| } |
| |
| virtual QUICConnectionInfoProvider * |
| connection_info() const override |
| { |
| return _info.get(); |
| } |
| virtual QUICConfig::scoped_config |
| config() const override |
| { |
| return _config; |
| } |
| virtual QUICRTTProvider * |
| rtt_provider() const override |
| { |
| return const_cast<QUICRTTMeasure *>(&_rtt_measure); |
| } |
| |
| virtual QUICPacketProtectionKeyInfo * |
| key_info() const override |
| { |
| return _key_info.get(); |
| } |
| |
| virtual QUICLDConfig & |
| ld_config() const override |
| { |
| return *_ld_config; |
| } |
| |
| virtual QUICCCConfig & |
| cc_config() const override |
| { |
| return *_cc_config; |
| } |
| |
| private: |
| QUICConfig::scoped_config _config; |
| QUICRTTMeasure _rtt_measure; |
| std::unique_ptr<QUICConnectionInfoProvider> _info; |
| std::unique_ptr<QUICPacketProtectionKeyInfo> _key_info; |
| std::unique_ptr<QUICLDConfig> _ld_config; |
| std::unique_ptr<QUICCCConfig> _cc_config; |
| }; |
| |
| class MockQUICLossDetector : public QUICLossDetector |
| { |
| public: |
| MockQUICLossDetector(MockQUICContext &context) |
| : QUICLossDetector(context, &_cc, &_rtt_measure, &this->_pinger, &this->_padder), |
| _padder(NetVConnectionContext_t::NET_VCONNECTION_UNSET) |
| { |
| } |
| void |
| rcv_frame(std::shared_ptr<const QUICFrame>) |
| { |
| } |
| |
| void |
| on_packet_sent(QUICPacketUPtr packet) |
| { |
| } |
| |
| private: |
| QUICPinger _pinger; |
| QUICPadder _padder; |
| QUICRTTMeasure _rtt_measure; |
| MockQUICCongestionController _cc; |
| }; |
| |
| class MockQUICApplication : public QUICApplication |
| { |
| public: |
| MockQUICApplication(QUICConnection *c) : QUICApplication(c) { SET_HANDLER(&MockQUICApplication::main_event_handler); } |
| |
| int |
| main_event_handler(int event, Event *data) |
| { |
| if (event == 12345) { |
| QUICStreamIO *stream_io = static_cast<QUICStreamIO *>(data->cookie); |
| stream_io->write_reenable(); |
| } |
| return EVENT_CONT; |
| } |
| |
| void |
| send(const uint8_t *data, size_t size, QUICStreamId stream_id) |
| { |
| QUICStreamIO *stream_io = this->_find_stream_io(stream_id); |
| stream_io->write(data, size); |
| |
| eventProcessor.schedule_imm(this, ET_CALL, 12345, stream_io); |
| } |
| }; |
| |
| class MockQUICPacket : public QUICPacket |
| { |
| public: |
| const IpEndpoint & |
| from() const override |
| { |
| return this->_from; |
| } |
| |
| const IpEndpoint & |
| to() const override |
| { |
| return this->_to; |
| } |
| |
| void |
| set_to(const IpEndpoint ep) |
| { |
| this->_to = ep; |
| } |
| |
| void |
| set_from(const IpEndpoint ep) |
| { |
| this->_from = ep; |
| } |
| |
| private: |
| IpEndpoint _to; |
| IpEndpoint _from; |
| }; |
| |
| class MockQUICHandshakeProtocol : public QUICHandshakeProtocol |
| { |
| public: |
| MockQUICHandshakeProtocol(QUICPacketProtectionKeyInfo &pp_key_info) : QUICHandshakeProtocol(pp_key_info) {} |
| |
| int |
| handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) override |
| { |
| return true; |
| } |
| |
| void |
| reset() override |
| { |
| } |
| |
| bool |
| is_handshake_finished() const override |
| { |
| return true; |
| } |
| |
| bool |
| is_ready_to_derive() const override |
| { |
| return true; |
| } |
| |
| int |
| initialize_key_materials(QUICConnectionId cid) override |
| { |
| return 0; |
| } |
| |
| const char * |
| negotiated_cipher_suite() const override |
| { |
| return nullptr; |
| } |
| |
| void |
| negotiated_application_name(const uint8_t **name, unsigned int *len) const override |
| { |
| *name = reinterpret_cast<const uint8_t *>("h3"); |
| *len = 2; |
| } |
| |
| QUICEncryptionLevel |
| current_encryption_level() const override |
| { |
| return QUICEncryptionLevel::INITIAL; |
| } |
| |
| void |
| abort_handshake() override |
| { |
| return; |
| } |
| |
| std::shared_ptr<const QUICTransportParameters> |
| local_transport_parameters() override |
| { |
| return nullptr; |
| } |
| |
| std::shared_ptr<const QUICTransportParameters> |
| remote_transport_parameters() override |
| { |
| return nullptr; |
| } |
| |
| void |
| set_local_transport_parameters(std::shared_ptr<const QUICTransportParameters> tp) override |
| { |
| } |
| |
| void |
| set_remote_transport_parameters(std::shared_ptr<const QUICTransportParameters> tp) override |
| { |
| } |
| }; |
| |
| class MockContinuation : public Continuation |
| { |
| public: |
| MockContinuation(Ptr<ProxyMutex> m) : Continuation(m) { SET_HANDLER(&MockContinuation::event_handler); } |
| int |
| event_handler(int event, Event *data) |
| { |
| return EVENT_CONT; |
| } |
| }; |
| |
| class MockQUICRTTProvider : public QUICRTTProvider |
| { |
| ink_hrtime |
| latest_rtt() const override |
| { |
| return HRTIME_MSECONDS(1); |
| } |
| |
| ink_hrtime |
| rttvar() const override |
| { |
| return HRTIME_MSECONDS(1); |
| } |
| |
| ink_hrtime |
| smoothed_rtt() const override |
| { |
| return HRTIME_MSECONDS(1); |
| } |
| |
| ink_hrtime |
| congestion_period(uint32_t threshold) const override |
| { |
| return HRTIME_MSECONDS(1); |
| } |
| }; |
| |
| class MockQUICTransferProgressProvider : public QUICTransferProgressProvider |
| { |
| public: |
| bool |
| is_transfer_goal_set() const override |
| { |
| return false; |
| } |
| |
| bool |
| is_transfer_complete() const override |
| { |
| return this->_is_transfer_complete || this->_transfer_progress >= this->_transfer_goal; |
| } |
| |
| bool |
| is_cancelled() const override |
| { |
| return this->_is_reset_complete; |
| } |
| |
| uint64_t |
| transfer_progress() const override |
| { |
| return this->_transfer_progress; |
| } |
| |
| uint64_t |
| transfer_goal() const override |
| { |
| return this->_transfer_goal; |
| } |
| |
| void |
| set_transfer_complete(bool b) |
| { |
| this->_is_transfer_complete = b; |
| } |
| |
| void |
| set_cancelled(bool b) |
| { |
| this->_is_reset_complete = b; |
| } |
| |
| void |
| set_transfer_progress(uint64_t v) |
| { |
| this->_transfer_progress = v; |
| } |
| |
| void |
| set_transfer_goal(uint64_t v) |
| { |
| this->_transfer_goal = v; |
| } |
| |
| private: |
| bool _is_transfer_complete = false; |
| bool _is_reset_complete = false; |
| uint64_t _transfer_progress = 0; |
| uint64_t _transfer_goal = UINT64_MAX; |
| }; |
| |
| class MockQUICFrameGenerator : public QUICFrameGenerator |
| { |
| public: |
| bool |
| will_generate_frame(QUICEncryptionLevel level, size_t connection_credit, bool ack_eliciting, uint32_t seq_num) override |
| { |
| return true; |
| } |
| |
| QUICFrame * |
| generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, |
| size_t current_packet_size, uint32_t seq_num) override |
| { |
| QUICFrame *frame = QUICFrameFactory::create_ping_frame(buf, 0, this); |
| QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); |
| this->_records_frame(0, std::move(info)); |
| return frame; |
| } |
| |
| int lost_frame_count = 0; |
| |
| private: |
| void |
| _on_frame_lost(QUICFrameInformationUPtr &info) override |
| { |
| lost_frame_count++; |
| } |
| }; |