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 "tscore/Diags.h"
25 
26 #include "QUICFrameRetransmitter.h"
27 #include "QUICFrameGenerator.h"
28 #include "QUICDebugNames.h"
29 
30 ClassAllocator<QUICFrameInformation> quicFrameInformationAllocator("quicFrameInformationAllocator");
31 
32 QUICFrame *
create_retransmitted_frame(uint8_t * buf,QUICEncryptionLevel level,uint16_t maximum_frame_size,QUICFrameId id,QUICFrameGenerator * owner)33 QUICFrameRetransmitter::create_retransmitted_frame(uint8_t *buf, QUICEncryptionLevel level, uint16_t maximum_frame_size,
34                                                    QUICFrameId id, QUICFrameGenerator *owner)
35 {
36   QUICFrame *frame = nullptr;
37   if (this->_lost_frame_info_queue.empty()) {
38     return frame;
39   }
40 
41   std::deque<QUICFrameInformationUPtr> tmp_queue;
42   for (auto it = this->_lost_frame_info_queue.begin(); it != this->_lost_frame_info_queue.end();
43        it      = this->_lost_frame_info_queue.begin()) {
44     QUICFrameInformationUPtr &info = *it;
45 
46     if (info->level != QUICEncryptionLevel::NONE && info->level != level) {
47       // skip unmapped info.
48       tmp_queue.push_back(std::move(info));
49       this->_lost_frame_info_queue.pop_front();
50       continue;
51     }
52 
53     switch (info->type) {
54     case QUICFrameType::STREAM:
55       frame = this->_create_stream_frame(buf, info, maximum_frame_size, tmp_queue, id, owner);
56       break;
57     case QUICFrameType::CRYPTO:
58       frame = this->_create_crypto_frame(buf, info, maximum_frame_size, tmp_queue, id, owner);
59       break;
60     default:
61       ink_assert("unknown frame type");
62       Error("unknown frame type: %s", QUICDebugNames::frame_type(info->type));
63     }
64 
65     this->_lost_frame_info_queue.pop_front();
66     if (frame != nullptr) {
67       break;
68     }
69   }
70 
71   this->_append_info_queue(tmp_queue);
72   return frame;
73 }
74 
75 void
save_frame_info(QUICFrameInformationUPtr info)76 QUICFrameRetransmitter::save_frame_info(QUICFrameInformationUPtr info)
77 {
78   for (auto type : RETRANSMITTED_FRAME_TYPE) {
79     if (type == info->type) {
80       this->_lost_frame_info_queue.push_back(std::move(info));
81       break;
82     }
83   }
84 }
85 
86 void
_append_info_queue(std::deque<QUICFrameInformationUPtr> & tmp_queue)87 QUICFrameRetransmitter::_append_info_queue(std::deque<QUICFrameInformationUPtr> &tmp_queue)
88 {
89   auto it = tmp_queue.begin();
90   while (it != tmp_queue.end()) {
91     this->_lost_frame_info_queue.push_back(std::move(*it));
92     tmp_queue.pop_front();
93     it = tmp_queue.begin();
94   }
95 }
96 
97 QUICFrame *
_create_stream_frame(uint8_t * buf,QUICFrameInformationUPtr & info,uint16_t maximum_frame_size,std::deque<QUICFrameInformationUPtr> & tmp_queue,QUICFrameId id,QUICFrameGenerator * owner)98 QUICFrameRetransmitter::_create_stream_frame(uint8_t *buf, QUICFrameInformationUPtr &info, uint16_t maximum_frame_size,
99                                              std::deque<QUICFrameInformationUPtr> &tmp_queue, QUICFrameId id,
100                                              QUICFrameGenerator *owner)
101 {
102   QUICFrame *frame             = nullptr;
103   StreamFrameInfo *stream_info = reinterpret_cast<StreamFrameInfo *>(info->data);
104 
105   static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24;
106   if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) {
107     tmp_queue.push_back(std::move(info));
108     return frame;
109   }
110 
111   // FIXME MAX_STREAM_FRAME_OVERHEAD is here and there
112   // These size calculation should not exist multiple places
113   uint64_t maximum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD;
114   if (maximum_data_size >= static_cast<uint64_t>(stream_info->block->size())) {
115     frame = QUICFrameFactory::create_stream_frame(buf, stream_info->block, stream_info->stream_id, stream_info->offset,
116                                                   stream_info->has_fin, true, true, id, owner);
117     ink_assert(frame->size() <= maximum_frame_size);
118     stream_info->block = nullptr;
119   } else {
120     frame = QUICFrameFactory::create_stream_frame(buf, stream_info->block, stream_info->stream_id, stream_info->offset, false, true,
121                                                   true, id, owner);
122     QUICStreamFrame *stream_frame = static_cast<QUICStreamFrame *>(frame);
123     IOBufferBlock *block          = stream_frame->data();
124     size_t over_length            = stream_frame->data_length() - maximum_data_size;
125     block->_end                   = std::max(block->start(), block->_end - over_length);
126     if (block->read_avail() == 0) {
127       // no payload
128       tmp_queue.push_back(std::move(info));
129       return nullptr;
130     }
131     stream_info->block->consume(stream_frame->data_length());
132     stream_info->offset += stream_frame->data_length();
133     ink_assert(frame->size() <= maximum_frame_size);
134     tmp_queue.push_back(std::move(info));
135     return frame;
136   }
137 
138   ink_assert(frame != nullptr);
139   return frame;
140 }
141 
142 QUICFrame *
_create_crypto_frame(uint8_t * buf,QUICFrameInformationUPtr & info,uint16_t maximum_frame_size,std::deque<QUICFrameInformationUPtr> & tmp_queue,QUICFrameId id,QUICFrameGenerator * owner)143 QUICFrameRetransmitter::_create_crypto_frame(uint8_t *buf, QUICFrameInformationUPtr &info, uint16_t maximum_frame_size,
144                                              std::deque<QUICFrameInformationUPtr> &tmp_queue, QUICFrameId id,
145                                              QUICFrameGenerator *owner)
146 {
147   CryptoFrameInfo *crypto_info = reinterpret_cast<CryptoFrameInfo *>(info->data);
148   // FIXME: has_offset and has_length should be configurable.
149   auto frame = QUICFrameFactory::create_crypto_frame(buf, crypto_info->block, crypto_info->offset, id, owner);
150   if (frame->size() > maximum_frame_size) {
151     QUICCryptoFrame *crypto_frame = static_cast<QUICCryptoFrame *>(frame);
152     if (crypto_frame->size() - crypto_frame->data_length() > maximum_frame_size) {
153       // header length is larger than maximum_frame_size.
154       tmp_queue.push_back(std::move(info));
155       return nullptr;
156     }
157 
158     IOBufferBlock *block = crypto_frame->data();
159     size_t over_length   = crypto_frame->size() - maximum_frame_size;
160     block->_end          = std::max(block->start(), block->_end - over_length);
161     if (block->read_avail() == 0) {
162       // no payload
163       tmp_queue.push_back(std::move(info));
164       return nullptr;
165     }
166 
167     crypto_info->block->consume(crypto_frame->data_length());
168     crypto_info->offset += crypto_frame->data_length();
169     ink_assert(frame->size() <= maximum_frame_size);
170     tmp_queue.push_back(std::move(info));
171     return frame;
172   }
173 
174   crypto_info->block = nullptr;
175   ink_assert(frame != nullptr);
176   return frame;
177 }
178 
179 bool
is_retransmited_frame_queue_empty() const180 QUICFrameRetransmitter::is_retransmited_frame_queue_empty() const
181 {
182   return this->_lost_frame_info_queue.empty();
183 }
184