1 /** @file
2  *
3  *  A brief file description
4  *
5  *  @section license License
6  *
7  *  Licensed to the Apache Software Foundation (ASF) under one
8  *  or more contributor license agreements.  See the NOTICE file
9  *  distributed with this work for additional information
10  *  regarding copyright ownership.  The ASF licenses this file
11  *  to you under the Apache License, Version 2.0 (the
12  *  "License"); you may not use this file except in compliance
13  *  with the License.  You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  *  Unless required by applicable law or agreed to in writing, software
18  *  distributed under the License is distributed on an "AS IS" BASIS,
19  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  *  See the License for the specific language governing permissions and
21  *  limitations under the License.
22  */
23 
24 #include "QUICCryptoStream.h"
25 
26 constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16;
27 
28 //
29 // QUICCryptoStream
30 //
QUICCryptoStream()31 QUICCryptoStream::QUICCryptoStream() : _received_stream_frame_buffer()
32 {
33   this->_read_buffer  = new_MIOBuffer(BUFFER_SIZE_INDEX_8K);
34   this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K);
35 
36   this->_read_buffer_reader  = this->_read_buffer->alloc_reader();
37   this->_write_buffer_reader = this->_write_buffer->alloc_reader();
38 }
39 
~QUICCryptoStream()40 QUICCryptoStream::~QUICCryptoStream()
41 {
42   // All readers will be deallocated
43   free_MIOBuffer(this->_read_buffer);
44   free_MIOBuffer(this->_write_buffer);
45 }
46 
47 /**
48  * Reset send/recv offset of stream
49  */
50 void
reset_send_offset()51 QUICCryptoStream::reset_send_offset()
52 {
53   this->_send_offset = 0;
54 }
55 
56 void
reset_recv_offset()57 QUICCryptoStream::reset_recv_offset()
58 {
59   this->_received_stream_frame_buffer.clear();
60 }
61 
62 QUICConnectionErrorUPtr
recv(const QUICCryptoFrame & frame)63 QUICCryptoStream::recv(const QUICCryptoFrame &frame)
64 {
65   // Make a copy and insert it into the receive buffer because the frame passed is temporal
66   QUICFrame *cloned             = new QUICCryptoFrame(frame);
67   QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(cloned);
68   if (error != nullptr) {
69     this->_received_stream_frame_buffer.clear();
70     return error;
71   }
72 
73   auto new_frame = this->_received_stream_frame_buffer.pop();
74   while (new_frame != nullptr) {
75     const QUICCryptoFrame *crypto_frame = static_cast<const QUICCryptoFrame *>(new_frame);
76 
77     this->_read_buffer->write(reinterpret_cast<uint8_t *>(crypto_frame->data()->start()), crypto_frame->data_length());
78 
79     delete new_frame;
80     new_frame = this->_received_stream_frame_buffer.pop();
81   }
82 
83   return nullptr;
84 }
85 
86 int64_t
read_avail()87 QUICCryptoStream::read_avail()
88 {
89   return this->_read_buffer_reader->read_avail();
90 }
91 
92 int64_t
read(uint8_t * buf,int64_t len)93 QUICCryptoStream::read(uint8_t *buf, int64_t len)
94 {
95   return this->_read_buffer_reader->read(buf, len);
96 }
97 
98 int64_t
write(const uint8_t * buf,int64_t len)99 QUICCryptoStream::write(const uint8_t *buf, int64_t len)
100 {
101   return this->_write_buffer->write(buf, len);
102 }
103 
104 bool
will_generate_frame(QUICEncryptionLevel level,size_t current_packet_size,bool ack_eliciting,uint32_t seq_num)105 QUICCryptoStream::will_generate_frame(QUICEncryptionLevel level, size_t current_packet_size, bool ack_eliciting, uint32_t seq_num)
106 {
107   return this->_write_buffer_reader->is_read_avail_more_than(0) || !this->is_retransmited_frame_queue_empty();
108 }
109 
110 /**
111  * @param connection_credit This is not used. Because CRYPTO frame is not flow-controlled
112  */
113 QUICFrame *
generate_frame(uint8_t * buf,QUICEncryptionLevel level,uint64_t,uint16_t maximum_frame_size,size_t current_packet_size,uint32_t seq_num)114 QUICCryptoStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */,
115                                  uint16_t maximum_frame_size, size_t current_packet_size, uint32_t seq_num)
116 {
117   QUICConnectionErrorUPtr error = nullptr;
118 
119   if (this->_reset_reason) {
120     return QUICFrameFactory::create_rst_stream_frame(buf, *this->_reset_reason);
121   }
122 
123   QUICFrame *frame = this->create_retransmitted_frame(buf, level, maximum_frame_size, this->_issue_frame_id(), this);
124   if (frame != nullptr) {
125     ink_assert(frame->type() == QUICFrameType::CRYPTO);
126     this->_records_crypto_frame(level, *static_cast<QUICCryptoFrame *>(frame));
127     return frame;
128   }
129 
130   if (maximum_frame_size <= MAX_CRYPTO_FRAME_OVERHEAD) {
131     return frame;
132   }
133 
134   uint64_t frame_payload_size = maximum_frame_size - MAX_CRYPTO_FRAME_OVERHEAD;
135   uint64_t bytes_avail        = this->_write_buffer_reader->read_avail();
136   frame_payload_size          = std::min(bytes_avail, frame_payload_size);
137   if (frame_payload_size == 0) {
138     return frame;
139   }
140 
141   Ptr<IOBufferBlock> block = make_ptr<IOBufferBlock>(this->_write_buffer_reader->get_current_block()->clone());
142   block->consume(this->_write_buffer_reader->start_offset);
143   block->_end = std::min(block->start() + frame_payload_size, block->_buf_end);
144   ink_assert(static_cast<uint64_t>(block->read_avail()) == frame_payload_size);
145 
146   frame = QUICFrameFactory::create_crypto_frame(buf, block, this->_send_offset, this->_issue_frame_id(), this);
147   this->_send_offset += frame_payload_size;
148   this->_write_buffer_reader->consume(frame_payload_size);
149   this->_records_crypto_frame(level, *static_cast<QUICCryptoFrame *>(frame));
150 
151   return frame;
152 }
153 
154 void
_on_frame_acked(QUICFrameInformationUPtr & info)155 QUICCryptoStream::_on_frame_acked(QUICFrameInformationUPtr &info)
156 {
157   ink_assert(info->type == QUICFrameType::CRYPTO);
158   CryptoFrameInfo *crypto_frame_info = reinterpret_cast<CryptoFrameInfo *>(info->data);
159   crypto_frame_info->block           = nullptr;
160 }
161 
162 void
_on_frame_lost(QUICFrameInformationUPtr & info)163 QUICCryptoStream::_on_frame_lost(QUICFrameInformationUPtr &info)
164 {
165   ink_assert(info->type == QUICFrameType::CRYPTO);
166   this->save_frame_info(std::move(info));
167 }
168