MySQL 8.0.37
Source Code Documentation
classic_protocol_codec_base.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2019, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_ROUTER_CLASSIC_PROTOCOL_CODEC_BASE_H_
27#define MYSQL_ROUTER_CLASSIC_PROTOCOL_CODEC_BASE_H_
28
29#include <cstddef> // size_t
30#include <cstdint> // uint8_t
31#include <limits>
32#include <system_error> // error_code
33#include <type_traits>
34#include <utility> // move
35
41
42namespace classic_protocol {
43
44// bytes needed to encode x bits
45//
46// bits | bytes
47// -----+------
48// 0 | 0
49// 1 | 1
50// ... | ...
51// 8 | 1
52// 9 | 2
53// ... | ...
54//
55constexpr size_t bytes_per_bits(size_t bits) { return (bits + 7) / 8; }
56
57static_assert(bytes_per_bits(0) == 0);
58static_assert(bytes_per_bits(1) == 1);
59static_assert(bytes_per_bits(8) == 1);
60static_assert(bytes_per_bits(9) == 2);
61
62/**
63 * Codec for a type.
64 *
65 * requirements for T:
66 * - size_t size()
67 * - stdx::expected<size_t, std::error_code> encode(net::mutable_buffer);
68 * - static stdx::expected<T, std::error_code> decode(buffer_sequence,
69 * capabilities);
70 */
71template <class T>
72class Codec;
73
74/**
75 * encode a message into a dynamic buffer.
76 *
77 * @param v message to encode
78 * @param caps protocol capabilities
79 * @param dyn_buffer dynamic buffer to write into
80 * @returns number of bytes written into dynamic buffer or std::error_code on
81 * error
82 */
83template <class T, class DynamicBuffer>
86 DynamicBuffer &&dyn_buffer) {
87 // static_assert(net::is_dynamic_buffer<DynamicBuffer>::value,
88 // "dyn_buffer MUST be a DynamicBuffer");
89
90 Codec<T> codec(v, caps);
91
92 const auto orig_size = dyn_buffer.size();
93 const auto codec_size = codec.size();
94
95 // reserve some space to write into
96 dyn_buffer.grow(codec_size);
97
98 const auto res = codec.encode(dyn_buffer.data(orig_size, codec_size));
99 if (!res) {
100 dyn_buffer.shrink(codec_size);
101 return res;
102 }
103
104 dyn_buffer.shrink(codec_size - res.value());
105
106 return res;
107}
108
109/**
110 * decode a message from a buffer.
111 *
112 * @param buffer buffer to read from
113 * @param caps protocol capabilities
114 * @tparam T the message class
115 * @returns number of bytes read from 'buffers' and a T on success, or
116 * std::error_code on error
117 */
118template <class T>
121 return Codec<T>::decode(buffer, caps);
122}
123
124/**
125 * decode a message from a buffer.
126 *
127 * @param buffer buffer to read from
128 * @param caps protocol capabilities
129 * @param args arguments that shall be forwarded to T's decode()
130 * @tparam T the message class
131 * @tparam Args Types of the extra arguments to be forwarded to T's decode()
132 * function.
133 * @returns number of bytes read from 'buffers' and a T on success, or
134 * std::error_code on error
135 */
136template <class T, class... Args>
139 // clang-format off
140 Args &&... args
141 // clang-format on
142) {
143 return Codec<T>::decode(buffer, caps, std::forward<Args>(args)...);
144}
145
146namespace impl {
147
148/**
149 * Generator of decoded Types of a buffer.
150 *
151 * - .step<wire::VarInt>()
152 */
154 public:
157
158 /**
159 * construct a DecodeBufferAccumulator.
160 *
161 * @param buffer a net::const_buffer
162 * @param caps classic-protocol capabilities
163 * @param consumed bytes to skip from the buffers
164 */
166 capabilities::value_type caps, size_t consumed = 0)
167 : buffer_(buffer), caps_(caps), consumed_(consumed) {}
168
169 /**
170 * decode a Type from the buffer sequence.
171 *
172 * if it succeeds, moves position in buffer forward and returns
173 * decoded Type, otherwise returns error and updates the global error-code in
174 * result()
175 *
176 * 'sz' is unlimited, the whole rest of the current buffer
177 * is passed to the decoder.
178 *
179 * If not, a slice of size 'sz' is taken. If there isn't at least 'sz' bytes
180 * in the buffer, it fails.
181 *
182 * @param sz limits the size of the current buffer.
183 */
184 template <class T>
186 size_t sz = std::numeric_limits<size_t>::max()) {
187 if (!res_) return stdx::make_unexpected(res_.error());
188
189 auto step_res = step_<T>(sz);
190
191 // capture the first failure
192 if (!step_res) res_ = stdx::make_unexpected(step_res.error());
193
194 return step_res;
195 }
196
197 /**
198 * try decoding a Type from the buffer sequence.
199 *
200 * if it succeeds, moves position in buffer-sequence forward and returns
201 * decoded Type, otherwise returns error and does NOT update the global
202 * error-code in result()
203 */
204 template <class T>
206 size_t sz = std::numeric_limits<size_t>::max()) {
207 if (!res_) return stdx::make_unexpected(res_.error());
208
209 return step_<T>(sz);
210 }
211
212 /**
213 * get result of the step().
214 *
215 * if a step() failed, result is the error-code of the first failed step()
216 *
217 * @returns consumed bytes by all steps(), or error of first failed step()
218 */
220 if (!res_) return res_;
221
222 return consumed_;
223 }
224
225 private:
226 template <class T>
228 size_t sz) {
229 auto buf = buffer_ + consumed_;
230
231 if (sz != std::numeric_limits<size_t>::max()) {
232 // not enough data.
233 if (buf.size() < sz) {
236 }
237 }
238
239 auto decode_res = Codec<T>::decode(net::buffer(buf, sz), caps_);
240 if (!decode_res) return stdx::make_unexpected(decode_res.error());
241
242 consumed_ += decode_res->first;
243 return decode_res->second;
244 }
245
248 size_t consumed_;
249
251};
252
253/**
254 * accumulator of encoded buffers.
255 *
256 * writes the .step()ed encoded types into buffer.
257 *
258 * EncodeBufferAccumulator(buffer, caps)
259 * .step(wire::VarInt(42))
260 * .step(wire::VarInt(512))
261 * .result()
262 *
263 * The class should be used together with EncodeSizeAccumulator which shares
264 * the same interface.
265 */
267 public:
269
270 /**
271 * construct a encode-buffer-accumulator.
272 *
273 * @param buffer mutable-buffer to encode into
274 * @param caps protocol capabilities
275 * @param consumed bytes already used in the in buffer
276 */
278 capabilities::value_type caps, size_t consumed = 0)
279 : buffer_{buffer}, caps_{caps}, consumed_{consumed} {}
280
281 /**
282 * encode a T into the buffer and move position forward.
283 *
284 * no-op of a previous step failed.
285 */
286 template <class T>
288 if (!res_) return *this;
289
290 auto res = Codec<T>(v, caps_).encode(buffer_ + consumed_);
291 if (!res) { // it failed.
292 res_ = res;
293 } else {
294 consumed_ += *res;
295 }
296
297 return *this;
298 }
299
300 /**
301 * get result the steps().
302 *
303 * @returns last used position in buffer, or first error in case of a step()
304 * failed.
305 */
307 if (!res_) return res_;
308
309 return {consumed_};
310 }
311
312 private:
315 size_t consumed_{};
316
318};
319
320/**
321 * accumulates the sizes of encoded T's.
322 *
323 * e.g. the size of tw
324 *
325 * EncodeSizeAccumulator(caps)
326 * .step(wire::VarInt(42)) // 1
327 * .step(wire::VarInt(512)) // 2
328 * .result() // = 3
329 *
330 * The class should be used together with EncodeBufferAccumulator which shares
331 * the same interface.
332 */
334 public:
335 using result_type = size_t;
336
337 /**
338 * construct a EncodeSizeAccumulator.
339 */
341 : caps_{caps} {}
342
343 /**
344 * accumulate the size() of encoded T.
345 *
346 * calls Codec<T>(v, caps).size()
347 */
348 template <class T>
349 constexpr EncodeSizeAccumulator &step(const T &v) noexcept {
350 consumed_ += Codec<T>(v, caps_).size();
351
352 return *this;
353 }
354
355 /**
356 * @returns size of all steps().
357 */
358 constexpr result_type result() const { return consumed_; }
359
360 private:
361 size_t consumed_{};
363};
364
365/**
366 * CRTP base for the Codec's encode part.
367 *
368 * derived classes must provide a 'accumulate_fields()' which
369 * maps each field by the Mapper and returns the result
370 *
371 * used by .size() and .encode() as both have to process the same
372 * fields in the same order, just with different mappers
373 */
374template <class T>
376 public:
378
379 constexpr size_t size() const noexcept {
380 return static_cast<const T *>(this)->accumulate_fields(
382 }
383
386 return static_cast<const T *>(this)->accumulate_fields(
388 }
389
390 constexpr capabilities::value_type caps() const noexcept { return caps_; }
391
392 private:
394};
395
396} // namespace impl
397} // namespace classic_protocol
398
399#endif
Codec for a type.
Definition: classic_protocol_codec_base.h:72
Generator of decoded Types of a buffer.
Definition: classic_protocol_codec_base.h:153
stdx::expected< typename Codec< T >::value_type, std::error_code > step_(size_t sz)
Definition: classic_protocol_codec_base.h:227
net::const_buffer buffer_
Definition: classic_protocol_codec_base.h:246
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:247
result_type res_
Definition: classic_protocol_codec_base.h:250
DecodeBufferAccumulator(const net::const_buffer &buffer, capabilities::value_type caps, size_t consumed=0)
construct a DecodeBufferAccumulator.
Definition: classic_protocol_codec_base.h:165
size_t consumed_
Definition: classic_protocol_codec_base.h:248
stdx::expected< typename Codec< T >::value_type, std::error_code > try_step(size_t sz=std::numeric_limits< size_t >::max())
try decoding a Type from the buffer sequence.
Definition: classic_protocol_codec_base.h:205
result_type result() const
get result of the step().
Definition: classic_protocol_codec_base.h:219
stdx::expected< typename Codec< T >::value_type, std::error_code > step(size_t sz=std::numeric_limits< size_t >::max())
decode a Type from the buffer sequence.
Definition: classic_protocol_codec_base.h:185
CRTP base for the Codec's encode part.
Definition: classic_protocol_codec_base.h:375
stdx::expected< size_t, std::error_code > encode(net::mutable_buffer buffer) const
Definition: classic_protocol_codec_base.h:384
constexpr size_t size() const noexcept
Definition: classic_protocol_codec_base.h:379
constexpr capabilities::value_type caps() const noexcept
Definition: classic_protocol_codec_base.h:390
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:393
constexpr EncodeBase(capabilities::value_type caps)
Definition: classic_protocol_codec_base.h:377
accumulator of encoded buffers.
Definition: classic_protocol_codec_base.h:266
result_type result() const
get result the steps().
Definition: classic_protocol_codec_base.h:306
EncodeBufferAccumulator & step(const T &v)
encode a T into the buffer and move position forward.
Definition: classic_protocol_codec_base.h:287
EncodeBufferAccumulator(net::mutable_buffer buffer, capabilities::value_type caps, size_t consumed=0)
construct a encode-buffer-accumulator.
Definition: classic_protocol_codec_base.h:277
const net::mutable_buffer buffer_
Definition: classic_protocol_codec_base.h:313
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:314
result_type res_
Definition: classic_protocol_codec_base.h:317
size_t consumed_
Definition: classic_protocol_codec_base.h:315
accumulates the sizes of encoded T's.
Definition: classic_protocol_codec_base.h:333
constexpr result_type result() const
Definition: classic_protocol_codec_base.h:358
constexpr EncodeSizeAccumulator(capabilities::value_type caps)
construct a EncodeSizeAccumulator.
Definition: classic_protocol_codec_base.h:340
size_t result_type
Definition: classic_protocol_codec_base.h:335
size_t consumed_
Definition: classic_protocol_codec_base.h:361
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:362
constexpr EncodeSizeAccumulator & step(const T &v) noexcept
accumulate the size() of encoded T.
Definition: classic_protocol_codec_base.h:349
Definition: buffer.h:135
Definition: buffer.h:113
constexpr const error_type & error() const &
Definition: expected.h:737
Definition: buf0block_hint.cc:30
std::bitset< 32 > value_type
Definition: classic_protocol_constants.h:73
Definition: classic_protocol_binary.h:39
stdx::expected< size_t, std::error_code > encode(const T &v, capabilities::value_type caps, DynamicBuffer &&dyn_buffer)
encode a message into a dynamic buffer.
Definition: classic_protocol_codec_base.h:84
std::error_code make_error_code(codec_errc e) noexcept
Definition: classic_protocol_codec_error.h:86
stdx::expected< std::pair< size_t, T >, std::error_code > decode(const net::const_buffer &buffer, capabilities::value_type caps, Args &&... args)
decode a message from a buffer.
Definition: classic_protocol_codec_base.h:137
stdx::expected< std::pair< size_t, T >, std::error_code > decode(const net::const_buffer &buffer, capabilities::value_type caps)
decode a message from a buffer.
Definition: classic_protocol_codec_base.h:119
constexpr size_t bytes_per_bits(size_t bits)
Definition: classic_protocol_codec_base.h:55
Definition: authentication.cc:36
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:420
constexpr auto make_unexpected(E &&e) -> unexpected< std::decay_t< E > >
Definition: expected.h:125