xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/qbone/qbone_session_base.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/qbone/qbone_session_base.h"
6 
7 #include <netinet/icmp6.h>
8 #include <netinet/ip6.h>
9 
10 #include <utility>
11 
12 #include "absl/strings/string_view.h"
13 #include "quiche/quic/core/quic_data_reader.h"
14 #include "quiche/quic/core/quic_types.h"
15 #include "quiche/quic/platform/api/quic_exported_stats.h"
16 #include "quiche/quic/platform/api/quic_logging.h"
17 #include "quiche/quic/platform/api/quic_testvalue.h"
18 #include "quiche/quic/qbone/platform/icmp_packet.h"
19 #include "quiche/quic/qbone/qbone_constants.h"
20 #include "quiche/common/platform/api/quiche_command_line_flags.h"
21 #include "quiche/common/platform/api/quiche_logging.h"
22 #include "quiche/common/platform/api/quiche_mem_slice.h"
23 #include "quiche/common/quiche_buffer_allocator.h"
24 
25 DEFINE_QUICHE_COMMAND_LINE_FLAG(
26     bool, qbone_close_ephemeral_frames, true,
27     "If true, we'll call CloseStream even when we receive ephemeral frames.");
28 
29 namespace quic {
30 
31 #define ENDPOINT \
32   (perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ")
33 
QboneSessionBase(QuicConnection * connection,Visitor * owner,const QuicConfig & config,const ParsedQuicVersionVector & supported_versions,QbonePacketWriter * writer)34 QboneSessionBase::QboneSessionBase(
35     QuicConnection* connection, Visitor* owner, const QuicConfig& config,
36     const ParsedQuicVersionVector& supported_versions,
37     QbonePacketWriter* writer)
38     : QuicSession(connection, owner, config, supported_versions,
39                   /*num_expected_unidirectional_static_streams = */ 0) {
40   set_writer(writer);
41   const uint32_t max_streams =
42       (std::numeric_limits<uint32_t>::max() / kMaxAvailableStreamsMultiplier) -
43       1;
44   this->config()->SetMaxBidirectionalStreamsToSend(max_streams);
45   if (VersionHasIetfQuicFrames(transport_version())) {
46     this->config()->SetMaxUnidirectionalStreamsToSend(max_streams);
47   }
48 }
49 
~QboneSessionBase()50 QboneSessionBase::~QboneSessionBase() {}
51 
Initialize()52 void QboneSessionBase::Initialize() {
53   crypto_stream_ = CreateCryptoStream();
54   QuicSession::Initialize();
55 }
56 
GetCryptoStream() const57 const QuicCryptoStream* QboneSessionBase::GetCryptoStream() const {
58   return crypto_stream_.get();
59 }
60 
GetMutableCryptoStream()61 QuicCryptoStream* QboneSessionBase::GetMutableCryptoStream() {
62   return crypto_stream_.get();
63 }
64 
CreateOutgoingStream()65 QuicStream* QboneSessionBase::CreateOutgoingStream() {
66   return ActivateDataStream(
67       CreateDataStream(GetNextOutgoingUnidirectionalStreamId()));
68 }
69 
OnStreamFrame(const QuicStreamFrame & frame)70 void QboneSessionBase::OnStreamFrame(const QuicStreamFrame& frame) {
71   if (frame.offset == 0 && frame.fin && frame.data_length > 0) {
72     ++num_ephemeral_packets_;
73     ProcessPacketFromPeer(
74         absl::string_view(frame.data_buffer, frame.data_length));
75     flow_controller()->AddBytesConsumed(frame.data_length);
76     // TODO(b/147817422): Add a counter for how many streams were actually
77     // closed here.
78     if (quiche::GetQuicheCommandLineFlag(FLAGS_qbone_close_ephemeral_frames)) {
79       ResetStream(frame.stream_id, QUIC_STREAM_CANCELLED);
80     }
81     return;
82   }
83   QuicSession::OnStreamFrame(frame);
84 }
85 
OnMessageReceived(absl::string_view message)86 void QboneSessionBase::OnMessageReceived(absl::string_view message) {
87   ++num_message_packets_;
88   ProcessPacketFromPeer(message);
89 }
90 
CreateIncomingStream(QuicStreamId id)91 QuicStream* QboneSessionBase::CreateIncomingStream(QuicStreamId id) {
92   return ActivateDataStream(CreateDataStream(id));
93 }
94 
CreateIncomingStream(PendingStream *)95 QuicStream* QboneSessionBase::CreateIncomingStream(PendingStream* /*pending*/) {
96   QUICHE_NOTREACHED();
97   return nullptr;
98 }
99 
ShouldKeepConnectionAlive() const100 bool QboneSessionBase::ShouldKeepConnectionAlive() const {
101   // QBONE connections stay alive until they're explicitly closed.
102   return true;
103 }
104 
CreateDataStream(QuicStreamId id)105 std::unique_ptr<QuicStream> QboneSessionBase::CreateDataStream(
106     QuicStreamId id) {
107   if (!IsEncryptionEstablished()) {
108     // Encryption not active so no stream created
109     return nullptr;
110   }
111 
112   if (IsIncomingStream(id)) {
113     ++num_streamed_packets_;
114     return std::make_unique<QboneReadOnlyStream>(id, this);
115   }
116 
117   return std::make_unique<QboneWriteOnlyStream>(id, this);
118 }
119 
ActivateDataStream(std::unique_ptr<QuicStream> stream)120 QuicStream* QboneSessionBase::ActivateDataStream(
121     std::unique_ptr<QuicStream> stream) {
122   // Transfer ownership of the data stream to the session via ActivateStream().
123   QuicStream* raw = stream.get();
124   if (stream) {
125     // Make QuicSession take ownership of the stream.
126     ActivateStream(std::move(stream));
127   }
128   return raw;
129 }
130 
SendPacketToPeer(absl::string_view packet)131 void QboneSessionBase::SendPacketToPeer(absl::string_view packet) {
132   if (crypto_stream_ == nullptr) {
133     QUIC_BUG(quic_bug_10987_1)
134         << "Attempting to send packet before encryption established";
135     return;
136   }
137 
138   if (send_packets_as_messages_) {
139     quiche::QuicheMemSlice slice(quiche::QuicheBuffer::Copy(
140         connection()->helper()->GetStreamSendBufferAllocator(), packet));
141     switch (SendMessage(absl::MakeSpan(&slice, 1), /*flush=*/true).status) {
142       case MESSAGE_STATUS_SUCCESS:
143         break;
144       case MESSAGE_STATUS_TOO_LARGE: {
145         if (packet.size() < sizeof(ip6_hdr)) {
146           QUIC_BUG(quic_bug_10987_2)
147               << "Dropped malformed packet: IPv6 header too short";
148           break;
149         }
150         auto* header = reinterpret_cast<const ip6_hdr*>(packet.begin());
151         icmp6_hdr icmp_header{};
152         icmp_header.icmp6_type = ICMP6_PACKET_TOO_BIG;
153         icmp_header.icmp6_mtu =
154             connection()->GetGuaranteedLargestMessagePayload();
155 
156         CreateIcmpPacket(header->ip6_dst, header->ip6_src, icmp_header, packet,
157                          [this](absl::string_view icmp_packet) {
158                            writer_->WritePacketToNetwork(icmp_packet.data(),
159                                                          icmp_packet.size());
160                          });
161         break;
162       }
163       case MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED:
164         QUIC_BUG(quic_bug_10987_3)
165             << "MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED";
166         break;
167       case MESSAGE_STATUS_UNSUPPORTED:
168         QUIC_BUG(quic_bug_10987_4) << "MESSAGE_STATUS_UNSUPPORTED";
169         break;
170       case MESSAGE_STATUS_BLOCKED:
171         QUIC_BUG(quic_bug_10987_5) << "MESSAGE_STATUS_BLOCKED";
172         break;
173       case MESSAGE_STATUS_INTERNAL_ERROR:
174         QUIC_BUG(quic_bug_10987_6) << "MESSAGE_STATUS_INTERNAL_ERROR";
175         break;
176     }
177     return;
178   }
179 
180   // QBONE streams are ephemeral.
181   QuicStream* stream = CreateOutgoingStream();
182   if (!stream) {
183     QUIC_BUG(quic_bug_10987_7) << "Failed to create an outgoing QBONE stream.";
184     return;
185   }
186 
187   QboneWriteOnlyStream* qbone_stream =
188       static_cast<QboneWriteOnlyStream*>(stream);
189   qbone_stream->WritePacketToQuicStream(packet);
190 }
191 
GetNumEphemeralPackets() const192 uint64_t QboneSessionBase::GetNumEphemeralPackets() const {
193   return num_ephemeral_packets_;
194 }
195 
GetNumStreamedPackets() const196 uint64_t QboneSessionBase::GetNumStreamedPackets() const {
197   return num_streamed_packets_;
198 }
199 
GetNumMessagePackets() const200 uint64_t QboneSessionBase::GetNumMessagePackets() const {
201   return num_message_packets_;
202 }
203 
GetNumFallbackToStream() const204 uint64_t QboneSessionBase::GetNumFallbackToStream() const {
205   return num_fallback_to_stream_;
206 }
207 
set_writer(QbonePacketWriter * writer)208 void QboneSessionBase::set_writer(QbonePacketWriter* writer) {
209   writer_ = writer;
210   quic::AdjustTestValue("quic_QbonePacketWriter", &writer_);
211 }
212 
213 }  // namespace quic
214