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