/src/libzmq/src/v1_decoder.cpp
Line | Count | Source |
1 | | /* SPDX-License-Identifier: MPL-2.0 */ |
2 | | |
3 | | #include "precompiled.hpp" |
4 | | #include <stdlib.h> |
5 | | #include <string.h> |
6 | | #include <limits> |
7 | | #include <limits.h> |
8 | | |
9 | | #include "decoder.hpp" |
10 | | #include "v1_decoder.hpp" |
11 | | #include "likely.hpp" |
12 | | #include "wire.hpp" |
13 | | #include "err.hpp" |
14 | | |
15 | | zmq::v1_decoder_t::v1_decoder_t (size_t bufsize_, int64_t maxmsgsize_) : |
16 | 0 | decoder_base_t<v1_decoder_t> (bufsize_), _max_msg_size (maxmsgsize_) |
17 | 0 | { |
18 | 0 | int rc = _in_progress.init (); |
19 | 0 | errno_assert (rc == 0); |
20 | | |
21 | | // At the beginning, read one byte and go to one_byte_size_ready state. |
22 | 0 | next_step (_tmpbuf, 1, &v1_decoder_t::one_byte_size_ready); |
23 | 0 | } |
24 | | |
25 | | zmq::v1_decoder_t::~v1_decoder_t () |
26 | 0 | { |
27 | 0 | const int rc = _in_progress.close (); |
28 | 0 | errno_assert (rc == 0); |
29 | 0 | } |
30 | | |
31 | | int zmq::v1_decoder_t::one_byte_size_ready (unsigned char const *) |
32 | 0 | { |
33 | | // First byte of size is read. If it is UCHAR_MAX (0xff) read 8-byte size. |
34 | | // Otherwise allocate the buffer for message data and read the |
35 | | // message data into it. |
36 | 0 | if (*_tmpbuf == UCHAR_MAX) |
37 | 0 | next_step (_tmpbuf, 8, &v1_decoder_t::eight_byte_size_ready); |
38 | 0 | else { |
39 | | // There has to be at least one byte (the flags) in the message). |
40 | 0 | if (!*_tmpbuf) { |
41 | 0 | errno = EPROTO; |
42 | 0 | return -1; |
43 | 0 | } |
44 | | |
45 | 0 | if (_max_msg_size >= 0 |
46 | 0 | && static_cast<int64_t> (*_tmpbuf - 1) > _max_msg_size) { |
47 | 0 | errno = EMSGSIZE; |
48 | 0 | return -1; |
49 | 0 | } |
50 | | |
51 | 0 | int rc = _in_progress.close (); |
52 | 0 | assert (rc == 0); |
53 | 0 | rc = _in_progress.init_size (*_tmpbuf - 1); |
54 | 0 | if (rc != 0) { |
55 | 0 | errno_assert (errno == ENOMEM); |
56 | 0 | rc = _in_progress.init (); |
57 | 0 | errno_assert (rc == 0); |
58 | 0 | errno = ENOMEM; |
59 | 0 | return -1; |
60 | 0 | } |
61 | | |
62 | 0 | next_step (_tmpbuf, 1, &v1_decoder_t::flags_ready); |
63 | 0 | } |
64 | 0 | return 0; |
65 | 0 | } |
66 | | |
67 | | int zmq::v1_decoder_t::eight_byte_size_ready (unsigned char const *) |
68 | 0 | { |
69 | | // 8-byte payload length is read. Allocate the buffer |
70 | | // for message body and read the message data into it. |
71 | 0 | const uint64_t payload_length = get_uint64 (_tmpbuf); |
72 | | |
73 | | // There has to be at least one byte (the flags) in the message). |
74 | 0 | if (payload_length == 0) { |
75 | 0 | errno = EPROTO; |
76 | 0 | return -1; |
77 | 0 | } |
78 | | |
79 | | // Message size must not exceed the maximum allowed size. |
80 | 0 | if (_max_msg_size >= 0 |
81 | 0 | && payload_length - 1 > static_cast<uint64_t> (_max_msg_size)) { |
82 | 0 | errno = EMSGSIZE; |
83 | 0 | return -1; |
84 | 0 | } |
85 | | |
86 | 0 | #ifndef __aarch64__ |
87 | | // Message size must fit within range of size_t data type. |
88 | 0 | if (payload_length - 1 > std::numeric_limits<size_t>::max ()) { |
89 | 0 | errno = EMSGSIZE; |
90 | 0 | return -1; |
91 | 0 | } |
92 | 0 | #endif |
93 | | |
94 | 0 | const size_t msg_size = static_cast<size_t> (payload_length - 1); |
95 | |
|
96 | 0 | int rc = _in_progress.close (); |
97 | 0 | assert (rc == 0); |
98 | 0 | rc = _in_progress.init_size (msg_size); |
99 | 0 | if (rc != 0) { |
100 | 0 | errno_assert (errno == ENOMEM); |
101 | 0 | rc = _in_progress.init (); |
102 | 0 | errno_assert (rc == 0); |
103 | 0 | errno = ENOMEM; |
104 | 0 | return -1; |
105 | 0 | } |
106 | | |
107 | 0 | next_step (_tmpbuf, 1, &v1_decoder_t::flags_ready); |
108 | 0 | return 0; |
109 | 0 | } |
110 | | |
111 | | int zmq::v1_decoder_t::flags_ready (unsigned char const *) |
112 | 0 | { |
113 | | // Store the flags from the wire into the message structure. |
114 | 0 | _in_progress.set_flags (_tmpbuf[0] & msg_t::more); |
115 | |
|
116 | 0 | next_step (_in_progress.data (), _in_progress.size (), |
117 | 0 | &v1_decoder_t::message_ready); |
118 | |
|
119 | 0 | return 0; |
120 | 0 | } |
121 | | |
122 | | int zmq::v1_decoder_t::message_ready (unsigned char const *) |
123 | 0 | { |
124 | | // Message is completely read. Push it further and start reading |
125 | | // new message. (in_progress is a 0-byte message after this point.) |
126 | 0 | next_step (_tmpbuf, 1, &v1_decoder_t::one_byte_size_ready); |
127 | 0 | return 1; |
128 | 0 | } |