decoder.hpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MPL-2.0 */
2 
3 #ifndef __ZMQ_DECODER_HPP_INCLUDED__
4 #define __ZMQ_DECODER_HPP_INCLUDED__
5 
6 #include <algorithm>
7 #include <cstddef>
8 #include <cstring>
9 
10 #include "decoder_allocators.hpp"
11 #include "err.hpp"
12 #include "i_decoder.hpp"
13 #include "stdint.hpp"
14 
15 namespace zmq
16 {
17 // Helper base class for decoders that know the amount of data to read
18 // in advance at any moment. Knowing the amount in advance is a property
19 // of the protocol used. 0MQ framing protocol is based size-prefixed
20 // paradigm, which qualifies it to be parsed by this class.
21 // On the other hand, XML-based transports (like XMPP or SOAP) don't allow
22 // for knowing the size of data to read in advance and should use different
23 // decoding algorithms.
24 //
25 // This class implements the state machine that parses the incoming buffer.
26 // Derived class should implement individual state machine actions.
27 //
28 // Buffer management is done by an allocator policy.
29 template <typename T, typename A = c_single_allocator>
30 class decoder_base_t : public i_decoder
31 {
32  public:
33  explicit decoder_base_t (const size_t buf_size_) :
34  _next (NULL), _read_pos (NULL), _to_read (0), _allocator (buf_size_)
35  {
36  _buf = _allocator.allocate ();
37  }
38 
39  ~decoder_base_t () ZMQ_OVERRIDE { _allocator.deallocate (); }
40 
41  // Returns a buffer to be filled with binary data.
42  void get_buffer (unsigned char **data_, std::size_t *size_) ZMQ_FINAL
43  {
44  _buf = _allocator.allocate ();
45 
46  // If we are expected to read large message, we'll opt for zero-
47  // copy, i.e. we'll ask caller to fill the data directly to the
48  // message. Note that subsequent read(s) are non-blocking, thus
49  // each single read reads at most SO_RCVBUF bytes at once not
50  // depending on how large is the chunk returned from here.
51  // As a consequence, large messages being received won't block
52  // other engines running in the same I/O thread for excessive
53  // amounts of time.
54  if (_to_read >= _allocator.size ()) {
55  *data_ = _read_pos;
56  *size_ = _to_read;
57  return;
58  }
59 
60  *data_ = _buf;
61  *size_ = _allocator.size ();
62  }
63 
64  // Processes the data in the buffer previously allocated using
65  // get_buffer function. size_ argument specifies number of bytes
66  // actually filled into the buffer. Function returns 1 when the
67  // whole message was decoded or 0 when more data is required.
68  // On error, -1 is returned and errno set accordingly.
69  // Number of bytes processed is returned in bytes_used_.
70  int decode (const unsigned char *data_,
71  std::size_t size_,
72  std::size_t &bytes_used_) ZMQ_FINAL
73  {
74  bytes_used_ = 0;
75 
76  // In case of zero-copy simply adjust the pointers, no copying
77  // is required. Also, run the state machine in case all the data
78  // were processed.
79  if (data_ == _read_pos) {
80  zmq_assert (size_ <= _to_read);
81  _read_pos += size_;
82  _to_read -= size_;
83  bytes_used_ = size_;
84 
85  while (!_to_read) {
86  const int rc =
87  (static_cast<T *> (this)->*_next) (data_ + bytes_used_);
88  if (rc != 0)
89  return rc;
90  }
91  return 0;
92  }
93 
94  while (bytes_used_ < size_) {
95  // Copy the data from buffer to the message.
96  const size_t to_copy = std::min (_to_read, size_ - bytes_used_);
97  // Only copy when destination address is different from the
98  // current address in the buffer.
99  if (_read_pos != data_ + bytes_used_) {
100  memcpy (_read_pos, data_ + bytes_used_, to_copy);
101  }
102 
103  _read_pos += to_copy;
104  _to_read -= to_copy;
105  bytes_used_ += to_copy;
106  // Try to get more space in the message to fill in.
107  // If none is available, return.
108  while (_to_read == 0) {
109  // pass current address in the buffer
110  const int rc =
111  (static_cast<T *> (this)->*_next) (data_ + bytes_used_);
112  if (rc != 0)
113  return rc;
114  }
115  }
116 
117  return 0;
118  }
119 
120  void resize_buffer (std::size_t new_size_) ZMQ_FINAL
121  {
122  _allocator.resize (new_size_);
123  }
124 
125  protected:
126  // Prototype of state machine action. Action should return false if
127  // it is unable to push the data to the system.
128  typedef int (T::*step_t) (unsigned char const *);
129 
130  // This function should be called from derived class to read data
131  // from the buffer and schedule next state machine action.
132  void next_step (void *read_pos_, std::size_t to_read_, step_t next_)
133  {
134  _read_pos = static_cast<unsigned char *> (read_pos_);
135  _to_read = to_read_;
136  _next = next_;
137  }
138 
139  A &get_allocator () { return _allocator; }
140 
141  private:
142  // Next step. If set to NULL, it means that associated data stream
143  // is dead. Note that there can be still data in the process in such
144  // case.
146 
147  // Where to store the read data.
148  unsigned char *_read_pos;
149 
150  // How much data to read before taking next step.
151  std::size_t _to_read;
152 
153  // The duffer for data to decode.
155  unsigned char *_buf;
156 
158 };
159 }
160 
161 #endif
zmq::ZMQ_FINAL
Definition: channel.hpp:17
zmq::decoder_base_t::~decoder_base_t
~decoder_base_t() ZMQ_OVERRIDE
Definition: decoder.hpp:39
data_
StringPiece data_
Definition: bytestream_unittest.cc:60
NULL
NULL
Definition: test_security_zap.cpp:405
decoder_allocators.hpp
zmq_assert
#define zmq_assert(x)
Definition: err.hpp:102
zmq::decoder_base_t::get_allocator
A & get_allocator()
Definition: decoder.hpp:139
T
#define T(upbtypeconst, upbtype, ctype, default_value)
zmq::decoder_base_t::_next
step_t _next
Definition: decoder.hpp:145
zmq::decoder_base_t::resize_buffer
void resize_buffer(std::size_t new_size_) ZMQ_FINAL
Definition: decoder.hpp:120
zmq
Definition: zmq.hpp:229
ZMQ_OVERRIDE
#define ZMQ_OVERRIDE
Definition: zmq.hpp:91
A
Definition: logging_striptest_main.cc:56
stdint.hpp
zmq::decoder_base_t::get_buffer
void get_buffer(unsigned char **data_, std::size_t *size_) ZMQ_FINAL
Definition: decoder.hpp:42
ZMQ_NON_COPYABLE_NOR_MOVABLE
#define ZMQ_NON_COPYABLE_NOR_MOVABLE(classname)
Definition: macros.hpp:58
zmq::decoder_base_t::step_t
int(T::* step_t)(unsigned char const *)
Definition: decoder.hpp:128
zmq::decoder_base_t::decode
int decode(const unsigned char *data_, std::size_t size_, std::size_t &bytes_used_) ZMQ_FINAL
Definition: decoder.hpp:70
zmq::i_decoder
Definition: i_decoder.hpp:15
zmq::decoder_base_t::_allocator
A _allocator
Definition: decoder.hpp:154
err.hpp
zmq::decoder_base_t::_buf
unsigned char * _buf
Definition: decoder.hpp:155
zmq::decoder_base_t::_to_read
std::size_t _to_read
Definition: decoder.hpp:151
zmq::decoder_base_t::decoder_base_t
decoder_base_t(const size_t buf_size_)
Definition: decoder.hpp:33
zmq::decoder_base_t::_read_pos
unsigned char * _read_pos
Definition: decoder.hpp:148
zmq::decoder_base_t::next_step
void next_step(void *read_pos_, std::size_t to_read_, step_t next_)
Definition: decoder.hpp:132
i_decoder.hpp
zmq::decoder_base_t
Definition: decoder.hpp:30


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:49