/src/libzmq/src/plain_client.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: MPL-2.0 */ |
2 | | |
3 | | #include "precompiled.hpp" |
4 | | #include "macros.hpp" |
5 | | |
6 | | #include <string> |
7 | | #include <limits.h> |
8 | | |
9 | | #include "msg.hpp" |
10 | | #include "err.hpp" |
11 | | #include "plain_client.hpp" |
12 | | #include "session_base.hpp" |
13 | | #include "plain_common.hpp" |
14 | | |
15 | | zmq::plain_client_t::plain_client_t (session_base_t *const session_, |
16 | | const options_t &options_) : |
17 | 0 | mechanism_base_t (session_, options_), _state (sending_hello) |
18 | 0 | { |
19 | 0 | } |
20 | | |
21 | | zmq::plain_client_t::~plain_client_t () |
22 | 0 | { |
23 | 0 | } |
24 | | |
25 | | int zmq::plain_client_t::next_handshake_command (msg_t *msg_) |
26 | 0 | { |
27 | 0 | int rc = 0; |
28 | |
|
29 | 0 | switch (_state) { |
30 | 0 | case sending_hello: |
31 | 0 | produce_hello (msg_); |
32 | 0 | _state = waiting_for_welcome; |
33 | 0 | break; |
34 | 0 | case sending_initiate: |
35 | 0 | produce_initiate (msg_); |
36 | 0 | _state = waiting_for_ready; |
37 | 0 | break; |
38 | 0 | default: |
39 | 0 | errno = EAGAIN; |
40 | 0 | rc = -1; |
41 | 0 | } |
42 | 0 | return rc; |
43 | 0 | } |
44 | | |
45 | | int zmq::plain_client_t::process_handshake_command (msg_t *msg_) |
46 | 0 | { |
47 | 0 | const unsigned char *cmd_data = |
48 | 0 | static_cast<unsigned char *> (msg_->data ()); |
49 | 0 | const size_t data_size = msg_->size (); |
50 | |
|
51 | 0 | int rc = 0; |
52 | 0 | if (data_size >= welcome_prefix_len |
53 | 0 | && !memcmp (cmd_data, welcome_prefix, welcome_prefix_len)) |
54 | 0 | rc = process_welcome (cmd_data, data_size); |
55 | 0 | else if (data_size >= ready_prefix_len |
56 | 0 | && !memcmp (cmd_data, ready_prefix, ready_prefix_len)) |
57 | 0 | rc = process_ready (cmd_data, data_size); |
58 | 0 | else if (data_size >= error_prefix_len |
59 | 0 | && !memcmp (cmd_data, error_prefix, error_prefix_len)) |
60 | 0 | rc = process_error (cmd_data, data_size); |
61 | 0 | else { |
62 | 0 | session->get_socket ()->event_handshake_failed_protocol ( |
63 | 0 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND); |
64 | 0 | errno = EPROTO; |
65 | 0 | rc = -1; |
66 | 0 | } |
67 | |
|
68 | 0 | if (rc == 0) { |
69 | 0 | rc = msg_->close (); |
70 | 0 | errno_assert (rc == 0); |
71 | 0 | rc = msg_->init (); |
72 | 0 | errno_assert (rc == 0); |
73 | 0 | } |
74 | |
|
75 | 0 | return rc; |
76 | 0 | } |
77 | | |
78 | | zmq::mechanism_t::status_t zmq::plain_client_t::status () const |
79 | 0 | { |
80 | 0 | switch (_state) { |
81 | 0 | case ready: |
82 | 0 | return mechanism_t::ready; |
83 | 0 | case error_command_received: |
84 | 0 | return mechanism_t::error; |
85 | 0 | default: |
86 | 0 | return mechanism_t::handshaking; |
87 | 0 | } |
88 | 0 | } |
89 | | |
90 | | void zmq::plain_client_t::produce_hello (msg_t *msg_) const |
91 | 0 | { |
92 | 0 | const std::string username = options.plain_username; |
93 | 0 | zmq_assert (username.length () <= UCHAR_MAX); |
94 | |
|
95 | 0 | const std::string password = options.plain_password; |
96 | 0 | zmq_assert (password.length () <= UCHAR_MAX); |
97 | |
|
98 | 0 | const size_t command_size = hello_prefix_len + brief_len_size |
99 | 0 | + username.length () + brief_len_size |
100 | 0 | + password.length (); |
101 | |
|
102 | 0 | const int rc = msg_->init_size (command_size); |
103 | 0 | errno_assert (rc == 0); |
104 | |
|
105 | 0 | unsigned char *ptr = static_cast<unsigned char *> (msg_->data ()); |
106 | 0 | memcpy (ptr, hello_prefix, hello_prefix_len); |
107 | 0 | ptr += hello_prefix_len; |
108 | |
|
109 | 0 | *ptr++ = static_cast<unsigned char> (username.length ()); |
110 | 0 | memcpy (ptr, username.c_str (), username.length ()); |
111 | 0 | ptr += username.length (); |
112 | |
|
113 | 0 | *ptr++ = static_cast<unsigned char> (password.length ()); |
114 | 0 | memcpy (ptr, password.c_str (), password.length ()); |
115 | 0 | } |
116 | | |
117 | | int zmq::plain_client_t::process_welcome (const unsigned char *cmd_data_, |
118 | | size_t data_size_) |
119 | 0 | { |
120 | 0 | LIBZMQ_UNUSED (cmd_data_); |
121 | |
|
122 | 0 | if (_state != waiting_for_welcome) { |
123 | 0 | session->get_socket ()->event_handshake_failed_protocol ( |
124 | 0 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND); |
125 | 0 | errno = EPROTO; |
126 | 0 | return -1; |
127 | 0 | } |
128 | 0 | if (data_size_ != welcome_prefix_len) { |
129 | 0 | session->get_socket ()->event_handshake_failed_protocol ( |
130 | 0 | session->get_endpoint (), |
131 | 0 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME); |
132 | 0 | errno = EPROTO; |
133 | 0 | return -1; |
134 | 0 | } |
135 | 0 | _state = sending_initiate; |
136 | 0 | return 0; |
137 | 0 | } |
138 | | |
139 | | void zmq::plain_client_t::produce_initiate (msg_t *msg_) const |
140 | 0 | { |
141 | 0 | make_command_with_basic_properties (msg_, initiate_prefix, |
142 | 0 | initiate_prefix_len); |
143 | 0 | } |
144 | | |
145 | | int zmq::plain_client_t::process_ready (const unsigned char *cmd_data_, |
146 | | size_t data_size_) |
147 | 0 | { |
148 | 0 | if (_state != waiting_for_ready) { |
149 | 0 | session->get_socket ()->event_handshake_failed_protocol ( |
150 | 0 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND); |
151 | 0 | errno = EPROTO; |
152 | 0 | return -1; |
153 | 0 | } |
154 | 0 | const int rc = parse_metadata (cmd_data_ + ready_prefix_len, |
155 | 0 | data_size_ - ready_prefix_len); |
156 | 0 | if (rc == 0) |
157 | 0 | _state = ready; |
158 | 0 | else |
159 | 0 | session->get_socket ()->event_handshake_failed_protocol ( |
160 | 0 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA); |
161 | |
|
162 | 0 | return rc; |
163 | 0 | } |
164 | | |
165 | | int zmq::plain_client_t::process_error (const unsigned char *cmd_data_, |
166 | | size_t data_size_) |
167 | 0 | { |
168 | 0 | if (_state != waiting_for_welcome && _state != waiting_for_ready) { |
169 | 0 | session->get_socket ()->event_handshake_failed_protocol ( |
170 | 0 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND); |
171 | 0 | errno = EPROTO; |
172 | 0 | return -1; |
173 | 0 | } |
174 | 0 | const size_t start_of_error_reason = error_prefix_len + brief_len_size; |
175 | 0 | if (data_size_ < start_of_error_reason) { |
176 | 0 | session->get_socket ()->event_handshake_failed_protocol ( |
177 | 0 | session->get_endpoint (), |
178 | 0 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR); |
179 | 0 | errno = EPROTO; |
180 | 0 | return -1; |
181 | 0 | } |
182 | 0 | const size_t error_reason_len = |
183 | 0 | static_cast<size_t> (cmd_data_[error_prefix_len]); |
184 | 0 | if (error_reason_len > data_size_ - start_of_error_reason) { |
185 | 0 | session->get_socket ()->event_handshake_failed_protocol ( |
186 | 0 | session->get_endpoint (), |
187 | 0 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR); |
188 | 0 | errno = EPROTO; |
189 | 0 | return -1; |
190 | 0 | } |
191 | 0 | const char *error_reason = |
192 | 0 | reinterpret_cast<const char *> (cmd_data_) + start_of_error_reason; |
193 | 0 | handle_error_reason (error_reason, error_reason_len); |
194 | 0 | _state = error_command_received; |
195 | 0 | return 0; |
196 | 0 | } |