| // Copyright (c) 2019 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h" | |
| #include <cstdint> | |
| #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" | |
| namespace quic { | |
| QuartcSendChannel::QuartcSendChannel(QuartcMultiplexer* multiplexer, | |
| uint64_t id, | |
| QuicBufferAllocator* allocator, | |
| Delegate* delegate) | |
| : multiplexer_(multiplexer), | |
| id_(id), | |
| encoded_length_(QuicDataWriter::GetVarInt62Len(id_)), | |
| allocator_(allocator), | |
| delegate_(delegate) {} | |
| QuartcStream* QuartcSendChannel::CreateOutgoingBidirectionalStream() { | |
| if (!session_) { | |
| QUIC_LOG(DFATAL) << "Session is not ready to write yet; channel_id=" << id_; | |
| return nullptr; | |
| } | |
| QuicMemSlice id_slice = EncodeChannelId(); | |
| QuartcStream* stream = session_->CreateOutgoingBidirectionalStream(); | |
| QuicConsumedData consumed = | |
| stream->WriteMemSlices(QuicMemSliceSpan(&id_slice), /*fin=*/false); | |
| DCHECK_EQ(consumed.bytes_consumed, encoded_length_); | |
| return stream; | |
| } | |
| bool QuartcSendChannel::SendOrQueueMessage(QuicMemSliceSpan message, | |
| int64_t datagram_id) { | |
| if (!session_) { | |
| QUIC_LOG(DFATAL) << "Session is not ready to write yet; channel_id=" << id_ | |
| << "datagram size=" << message.total_length(); | |
| return false; | |
| } | |
| QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); // Empty storage. | |
| storage.Append(EncodeChannelId()); | |
| message.ConsumeAll( | |
| [&storage](QuicMemSlice slice) { storage.Append(std::move(slice)); }); | |
| // Allocate a unique datagram id so that notifications can be routed back to | |
| // the right send channel. | |
| int64_t unique_datagram_id = multiplexer_->AllocateDatagramId(this); | |
| multiplexer_to_user_datagram_ids_[unique_datagram_id] = datagram_id; | |
| return session_->SendOrQueueMessage(storage.ToSpan(), unique_datagram_id); | |
| } | |
| void QuartcSendChannel::OnMessageSent(int64_t datagram_id) { | |
| // Map back to the caller-chosen |datagram_id|. | |
| datagram_id = multiplexer_to_user_datagram_ids_[datagram_id]; | |
| delegate_->OnMessageSent(datagram_id); | |
| } | |
| void QuartcSendChannel::OnMessageAcked(int64_t datagram_id, | |
| QuicTime receive_timestamp) { | |
| // Map back to the caller-chosen |datagram_id|. | |
| auto it = multiplexer_to_user_datagram_ids_.find(datagram_id); | |
| if (it == multiplexer_to_user_datagram_ids_.end()) { | |
| QUIC_LOG(DFATAL) << "Datagram acked/lost multiple times; datagram_id=" | |
| << datagram_id; | |
| return; | |
| } | |
| delegate_->OnMessageAcked(it->second, receive_timestamp); | |
| multiplexer_to_user_datagram_ids_.erase(it); | |
| } | |
| void QuartcSendChannel::OnMessageLost(int64_t datagram_id) { | |
| // Map back to the caller-chosen |datagram_id|. | |
| auto it = multiplexer_to_user_datagram_ids_.find(datagram_id); | |
| if (it == multiplexer_to_user_datagram_ids_.end()) { | |
| QUIC_LOG(DFATAL) << "Datagram acked/lost multiple times; datagram_id=" | |
| << datagram_id; | |
| return; | |
| } | |
| delegate_->OnMessageLost(it->second); | |
| multiplexer_to_user_datagram_ids_.erase(it); | |
| } | |
| void QuartcSendChannel::OnSessionCreated(QuartcSession* session) { | |
| session_ = session; | |
| } | |
| QuicMemSlice QuartcSendChannel::EncodeChannelId() { | |
| QuicMemSlice id_slice(allocator_, encoded_length_); | |
| QuicDataWriter writer(encoded_length_, const_cast<char*>(id_slice.data())); | |
| writer.WriteVarInt62(id_); | |
| return id_slice; | |
| } | |
| QuartcMultiplexer::QuartcMultiplexer( | |
| QuicBufferAllocator* allocator, | |
| QuartcSessionEventDelegate* session_delegate, | |
| QuartcReceiveChannel* default_receive_channel) | |
| : allocator_(allocator), | |
| session_delegate_(session_delegate), | |
| default_receive_channel_(default_receive_channel) { | |
| CHECK_NE(session_delegate_, nullptr); | |
| CHECK_NE(default_receive_channel_, nullptr); | |
| } | |
| QuartcSendChannel* QuartcMultiplexer::CreateSendChannel( | |
| uint64_t channel_id, | |
| QuartcSendChannel::Delegate* delegate) { | |
| send_channels_.push_back(std::make_unique<QuartcSendChannel>( | |
| this, channel_id, allocator_, delegate)); | |
| if (session_) { | |
| send_channels_.back()->OnSessionCreated(session_); | |
| } | |
| return send_channels_.back().get(); | |
| } | |
| void QuartcMultiplexer::RegisterReceiveChannel(uint64_t channel_id, | |
| QuartcReceiveChannel* channel) { | |
| if (channel == nullptr) { | |
| receive_channels_.erase(channel_id); | |
| return; | |
| } | |
| auto& registered_channel = receive_channels_[channel_id]; | |
| if (registered_channel) { | |
| QUIC_LOG(DFATAL) << "Attempted to overwrite existing channel_id=" | |
| << channel_id; | |
| return; | |
| } | |
| registered_channel = channel; | |
| } | |
| int64_t QuartcMultiplexer::AllocateDatagramId(QuartcSendChannel* channel) { | |
| send_channels_by_datagram_id_[next_datagram_id_] = channel; | |
| return next_datagram_id_++; | |
| } | |
| void QuartcMultiplexer::OnSessionCreated(QuartcSession* session) { | |
| for (auto& channel : send_channels_) { | |
| channel->OnSessionCreated(session); | |
| } | |
| session_ = session; | |
| session_delegate_->OnSessionCreated(session); | |
| } | |
| void QuartcMultiplexer::OnCryptoHandshakeComplete() { | |
| session_delegate_->OnCryptoHandshakeComplete(); | |
| } | |
| void QuartcMultiplexer::OnConnectionWritable() { | |
| session_delegate_->OnConnectionWritable(); | |
| } | |
| void QuartcMultiplexer::OnIncomingStream(QuartcStream* stream) { | |
| stream->SetDelegate(this); | |
| } | |
| void QuartcMultiplexer::OnCongestionControlChange( | |
| QuicBandwidth bandwidth_estimate, | |
| QuicBandwidth pacing_rate, | |
| QuicTime::Delta latest_rtt) { | |
| session_delegate_->OnCongestionControlChange(bandwidth_estimate, pacing_rate, | |
| latest_rtt); | |
| } | |
| void QuartcMultiplexer::OnConnectionClosed( | |
| const QuicConnectionCloseFrame& frame, | |
| ConnectionCloseSource source) { | |
| session_delegate_->OnConnectionClosed(frame, source); | |
| } | |
| void QuartcMultiplexer::OnMessageReceived(QuicStringPiece message) { | |
| QuicDataReader reader(message); | |
| QuicVariableLengthIntegerLength channel_id_length = | |
| reader.PeekVarInt62Length(); | |
| uint64_t channel_id; | |
| if (!reader.ReadVarInt62(&channel_id)) { | |
| QUIC_LOG(DFATAL) << "Received message without properly encoded channel id"; | |
| return; | |
| } | |
| QuartcReceiveChannel* channel = default_receive_channel_; | |
| auto it = receive_channels_.find(channel_id); | |
| if (it != receive_channels_.end()) { | |
| channel = it->second; | |
| } | |
| channel->OnMessageReceived(channel_id, message.substr(channel_id_length)); | |
| } | |
| void QuartcMultiplexer::OnMessageSent(int64_t datagram_id) { | |
| auto it = send_channels_by_datagram_id_.find(datagram_id); | |
| if (it == send_channels_by_datagram_id_.end()) { | |
| return; | |
| } | |
| it->second->OnMessageSent(datagram_id); | |
| } | |
| void QuartcMultiplexer::OnMessageAcked(int64_t datagram_id, | |
| QuicTime receive_timestamp) { | |
| auto it = send_channels_by_datagram_id_.find(datagram_id); | |
| if (it == send_channels_by_datagram_id_.end()) { | |
| return; | |
| } | |
| it->second->OnMessageAcked(datagram_id, receive_timestamp); | |
| send_channels_by_datagram_id_.erase(it); | |
| } | |
| void QuartcMultiplexer::OnMessageLost(int64_t datagram_id) { | |
| auto it = send_channels_by_datagram_id_.find(datagram_id); | |
| if (it == send_channels_by_datagram_id_.end()) { | |
| return; | |
| } | |
| it->second->OnMessageLost(datagram_id); | |
| send_channels_by_datagram_id_.erase(it); | |
| } | |
| size_t QuartcMultiplexer::OnReceived(QuartcStream* stream, | |
| iovec* iov, | |
| size_t iov_length, | |
| bool /*fin*/) { | |
| if (iov == nullptr || iov_length <= 0) { | |
| return 0; | |
| } | |
| QuicDataReader reader(static_cast<char*>(iov[0].iov_base), iov[0].iov_len); | |
| QuicVariableLengthIntegerLength channel_id_length = | |
| reader.PeekVarInt62Length(); | |
| uint64_t channel_id; | |
| if (reader.BytesRemaining() >= channel_id_length) { | |
| // Fast path, have enough data to read immediately. | |
| if (!reader.ReadVarInt62(&channel_id)) { | |
| return 0; | |
| } | |
| } else { | |
| // Slow path, need to coalesce multiple iovecs. | |
| std::string data; | |
| for (size_t i = 0; i < iov_length; ++i) { | |
| data += std::string(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); | |
| } | |
| QuicDataReader combined_reader(data); | |
| if (!combined_reader.ReadVarInt62(&channel_id)) { | |
| return 0; | |
| } | |
| } | |
| QuartcReceiveChannel* channel = default_receive_channel_; | |
| auto it = receive_channels_.find(channel_id); | |
| if (it != receive_channels_.end()) { | |
| channel = it->second; | |
| } | |
| channel->OnIncomingStream(channel_id, stream); | |
| return channel_id_length; | |
| } | |
| void QuartcMultiplexer::OnClose(QuartcStream* /*stream*/) {} | |
| void QuartcMultiplexer::OnBufferChanged(QuartcStream* /*stream*/) {} | |
| } // namespace quic |