1 /*
2 Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
3
4 This file is part of libzmq, the ZeroMQ core engine in C++.
5
6 libzmq is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License (LGPL) as published
8 by the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 As a special exception, the Contributors give you permission to link
12 this library with independent modules to produce an executable,
13 regardless of the license terms of these independent modules, and to
14 copy and distribute the resulting executable under terms of your choice,
15 provided that you also meet, for each linked independent module, the
16 terms and conditions of the license of that module. An independent
17 module is a module which is not derived from or based on this library.
18 If you modify this library, you must extend this exception to your
19 version of the library.
20
21 libzmq is distributed in the hope that it will be useful, but WITHOUT
22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
24 License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 */
29
30 #include "precompiled.hpp"
31 #include <string.h>
32 #include <limits.h>
33
34 #include "mechanism.hpp"
35 #include "options.hpp"
36 #include "msg.hpp"
37 #include "err.hpp"
38 #include "wire.hpp"
39 #include "session_base.hpp"
40
mechanism_t(const options_t & options_)41 zmq::mechanism_t::mechanism_t (const options_t &options_) : options (options_)
42 {
43 }
44
~mechanism_t()45 zmq::mechanism_t::~mechanism_t ()
46 {
47 }
48
set_peer_routing_id(const void * id_ptr_,size_t id_size_)49 void zmq::mechanism_t::set_peer_routing_id (const void *id_ptr_,
50 size_t id_size_)
51 {
52 _routing_id.set (static_cast<const unsigned char *> (id_ptr_), id_size_);
53 }
54
peer_routing_id(msg_t * msg_)55 void zmq::mechanism_t::peer_routing_id (msg_t *msg_)
56 {
57 const int rc = msg_->init_size (_routing_id.size ());
58 errno_assert (rc == 0);
59 memcpy (msg_->data (), _routing_id.data (), _routing_id.size ());
60 msg_->set_flags (msg_t::routing_id);
61 }
62
set_user_id(const void * user_id_,size_t size_)63 void zmq::mechanism_t::set_user_id (const void *user_id_, size_t size_)
64 {
65 _user_id.set (static_cast<const unsigned char *> (user_id_), size_);
66 _zap_properties.ZMQ_MAP_INSERT_OR_EMPLACE (
67 std::string (ZMQ_MSG_PROPERTY_USER_ID),
68 std::string (reinterpret_cast<const char *> (user_id_), size_));
69 }
70
get_user_id() const71 const zmq::blob_t &zmq::mechanism_t::get_user_id () const
72 {
73 return _user_id;
74 }
75
76 const char socket_type_pair[] = "PAIR";
77 const char socket_type_pub[] = "PUB";
78 const char socket_type_sub[] = "SUB";
79 const char socket_type_req[] = "REQ";
80 const char socket_type_rep[] = "REP";
81 const char socket_type_dealer[] = "DEALER";
82 const char socket_type_router[] = "ROUTER";
83 const char socket_type_pull[] = "PULL";
84 const char socket_type_push[] = "PUSH";
85 const char socket_type_xpub[] = "XPUB";
86 const char socket_type_xsub[] = "XSUB";
87 const char socket_type_stream[] = "STREAM";
88 #ifdef ZMQ_BUILD_DRAFT_API
89 const char socket_type_server[] = "SERVER";
90 const char socket_type_client[] = "CLIENT";
91 const char socket_type_radio[] = "RADIO";
92 const char socket_type_dish[] = "DISH";
93 const char socket_type_gather[] = "GATHER";
94 const char socket_type_scatter[] = "SCATTER";
95 const char socket_type_dgram[] = "DGRAM";
96 const char socket_type_peer[] = "PEER";
97 const char socket_type_channel[] = "CHANNEL";
98 #endif
99
socket_type_string(int socket_type_)100 const char *zmq::mechanism_t::socket_type_string (int socket_type_)
101 {
102 // TODO the order must of the names must correspond to the values resp. order of ZMQ_* socket type definitions in zmq.h!
103 static const char *names[] = {socket_type_pair, socket_type_pub,
104 socket_type_sub, socket_type_req,
105 socket_type_rep, socket_type_dealer,
106 socket_type_router, socket_type_pull,
107 socket_type_push, socket_type_xpub,
108 socket_type_xsub, socket_type_stream,
109 #ifdef ZMQ_BUILD_DRAFT_API
110 socket_type_server, socket_type_client,
111 socket_type_radio, socket_type_dish,
112 socket_type_gather, socket_type_scatter,
113 socket_type_dgram, socket_type_peer,
114 socket_type_channel
115 #endif
116 };
117 static const size_t names_count = sizeof (names) / sizeof (names[0]);
118 zmq_assert (socket_type_ >= 0
119 && socket_type_ < static_cast<int> (names_count));
120 return names[socket_type_];
121 }
122
123 const size_t name_len_size = sizeof (unsigned char);
124 const size_t value_len_size = sizeof (uint32_t);
125
property_len(size_t name_len_,size_t value_len_)126 static size_t property_len (size_t name_len_, size_t value_len_)
127 {
128 return name_len_size + name_len_ + value_len_size + value_len_;
129 }
130
name_len(const char * name_)131 static size_t name_len (const char *name_)
132 {
133 const size_t name_len = strlen (name_);
134 zmq_assert (name_len <= UCHAR_MAX);
135 return name_len;
136 }
137
add_property(unsigned char * ptr_,size_t ptr_capacity_,const char * name_,const void * value_,size_t value_len_)138 size_t zmq::mechanism_t::add_property (unsigned char *ptr_,
139 size_t ptr_capacity_,
140 const char *name_,
141 const void *value_,
142 size_t value_len_)
143 {
144 const size_t name_len = ::name_len (name_);
145 const size_t total_len = ::property_len (name_len, value_len_);
146 zmq_assert (total_len <= ptr_capacity_);
147
148 *ptr_ = static_cast<unsigned char> (name_len);
149 ptr_ += name_len_size;
150 memcpy (ptr_, name_, name_len);
151 ptr_ += name_len;
152 zmq_assert (value_len_ <= 0x7FFFFFFF);
153 put_uint32 (ptr_, static_cast<uint32_t> (value_len_));
154 ptr_ += value_len_size;
155 memcpy (ptr_, value_, value_len_);
156
157 return total_len;
158 }
159
property_len(const char * name_,size_t value_len_)160 size_t zmq::mechanism_t::property_len (const char *name_, size_t value_len_)
161 {
162 return ::property_len (name_len (name_), value_len_);
163 }
164
165 #define ZMTP_PROPERTY_SOCKET_TYPE "Socket-Type"
166 #define ZMTP_PROPERTY_IDENTITY "Identity"
167
add_basic_properties(unsigned char * ptr_,size_t ptr_capacity_) const168 size_t zmq::mechanism_t::add_basic_properties (unsigned char *ptr_,
169 size_t ptr_capacity_) const
170 {
171 unsigned char *ptr = ptr_;
172
173 // Add socket type property
174 const char *socket_type = socket_type_string (options.type);
175 ptr += add_property (ptr, ptr_capacity_, ZMTP_PROPERTY_SOCKET_TYPE,
176 socket_type, strlen (socket_type));
177
178 // Add identity (aka routing id) property
179 if (options.type == ZMQ_REQ || options.type == ZMQ_DEALER
180 || options.type == ZMQ_ROUTER) {
181 ptr += add_property (ptr, ptr_capacity_ - (ptr - ptr_),
182 ZMTP_PROPERTY_IDENTITY, options.routing_id,
183 options.routing_id_size);
184 }
185
186
187 for (std::map<std::string, std::string>::const_iterator
188 it = options.app_metadata.begin (),
189 end = options.app_metadata.end ();
190 it != end; ++it) {
191 ptr +=
192 add_property (ptr, ptr_capacity_ - (ptr - ptr_), it->first.c_str (),
193 it->second.c_str (), strlen (it->second.c_str ()));
194 }
195
196 return ptr - ptr_;
197 }
198
basic_properties_len() const199 size_t zmq::mechanism_t::basic_properties_len () const
200 {
201 const char *socket_type = socket_type_string (options.type);
202 size_t meta_len = 0;
203
204 for (std::map<std::string, std::string>::const_iterator
205 it = options.app_metadata.begin (),
206 end = options.app_metadata.end ();
207 it != end; ++it) {
208 meta_len +=
209 property_len (it->first.c_str (), strlen (it->second.c_str ()));
210 }
211
212 return property_len (ZMTP_PROPERTY_SOCKET_TYPE, strlen (socket_type))
213 + meta_len
214 + ((options.type == ZMQ_REQ || options.type == ZMQ_DEALER
215 || options.type == ZMQ_ROUTER)
216 ? property_len (ZMTP_PROPERTY_IDENTITY, options.routing_id_size)
217 : 0);
218 }
219
make_command_with_basic_properties(msg_t * msg_,const char * prefix_,size_t prefix_len_) const220 void zmq::mechanism_t::make_command_with_basic_properties (
221 msg_t *msg_, const char *prefix_, size_t prefix_len_) const
222 {
223 const size_t command_size = prefix_len_ + basic_properties_len ();
224 const int rc = msg_->init_size (command_size);
225 errno_assert (rc == 0);
226
227 unsigned char *ptr = static_cast<unsigned char *> (msg_->data ());
228
229 // Add prefix
230 memcpy (ptr, prefix_, prefix_len_);
231 ptr += prefix_len_;
232
233 add_basic_properties (
234 ptr, command_size - (ptr - static_cast<unsigned char *> (msg_->data ())));
235 }
236
parse_metadata(const unsigned char * ptr_,size_t length_,bool zap_flag_)237 int zmq::mechanism_t::parse_metadata (const unsigned char *ptr_,
238 size_t length_,
239 bool zap_flag_)
240 {
241 size_t bytes_left = length_;
242
243 while (bytes_left > 1) {
244 const size_t name_length = static_cast<size_t> (*ptr_);
245 ptr_ += name_len_size;
246 bytes_left -= name_len_size;
247 if (bytes_left < name_length)
248 break;
249
250 const std::string name =
251 std::string (reinterpret_cast<const char *> (ptr_), name_length);
252 ptr_ += name_length;
253 bytes_left -= name_length;
254 if (bytes_left < value_len_size)
255 break;
256
257 const size_t value_length = static_cast<size_t> (get_uint32 (ptr_));
258 ptr_ += value_len_size;
259 bytes_left -= value_len_size;
260 if (bytes_left < value_length)
261 break;
262
263 const uint8_t *value = ptr_;
264 ptr_ += value_length;
265 bytes_left -= value_length;
266
267 if (name == ZMTP_PROPERTY_IDENTITY && options.recv_routing_id)
268 set_peer_routing_id (value, value_length);
269 else if (name == ZMTP_PROPERTY_SOCKET_TYPE) {
270 if (!check_socket_type (reinterpret_cast<const char *> (value),
271 value_length)) {
272 errno = EINVAL;
273 return -1;
274 }
275 } else {
276 const int rc = property (name, value, value_length);
277 if (rc == -1)
278 return -1;
279 }
280 (zap_flag_ ? _zap_properties : _zmtp_properties)
281 .ZMQ_MAP_INSERT_OR_EMPLACE (
282 name,
283 std::string (reinterpret_cast<const char *> (value), value_length));
284 }
285 if (bytes_left > 0) {
286 errno = EPROTO;
287 return -1;
288 }
289 return 0;
290 }
291
property(const std::string &,const void *,size_t)292 int zmq::mechanism_t::property (const std::string & /* name_ */,
293 const void * /* value_ */,
294 size_t /* length_ */)
295 {
296 // Default implementation does not check
297 // property values and returns 0 to signal success.
298 return 0;
299 }
300
301 template <size_t N>
strequals(const char * actual_type_,const size_t actual_len_,const char (& expected_type_)[N])302 static bool strequals (const char *actual_type_,
303 const size_t actual_len_,
304 const char (&expected_type_)[N])
305 {
306 return actual_len_ == N - 1
307 && memcmp (actual_type_, expected_type_, N - 1) == 0;
308 }
309
check_socket_type(const char * type_,const size_t len_) const310 bool zmq::mechanism_t::check_socket_type (const char *type_,
311 const size_t len_) const
312 {
313 switch (options.type) {
314 case ZMQ_REQ:
315 return strequals (type_, len_, socket_type_rep)
316 || strequals (type_, len_, socket_type_router);
317 case ZMQ_REP:
318 return strequals (type_, len_, socket_type_req)
319 || strequals (type_, len_, socket_type_dealer);
320 case ZMQ_DEALER:
321 return strequals (type_, len_, socket_type_rep)
322 || strequals (type_, len_, socket_type_dealer)
323 || strequals (type_, len_, socket_type_router);
324 case ZMQ_ROUTER:
325 return strequals (type_, len_, socket_type_req)
326 || strequals (type_, len_, socket_type_dealer)
327 || strequals (type_, len_, socket_type_router);
328 case ZMQ_PUSH:
329 return strequals (type_, len_, socket_type_pull);
330 case ZMQ_PULL:
331 return strequals (type_, len_, socket_type_push);
332 case ZMQ_PUB:
333 return strequals (type_, len_, socket_type_sub)
334 || strequals (type_, len_, socket_type_xsub);
335 case ZMQ_SUB:
336 return strequals (type_, len_, socket_type_pub)
337 || strequals (type_, len_, socket_type_xpub);
338 case ZMQ_XPUB:
339 return strequals (type_, len_, socket_type_sub)
340 || strequals (type_, len_, socket_type_xsub);
341 case ZMQ_XSUB:
342 return strequals (type_, len_, socket_type_pub)
343 || strequals (type_, len_, socket_type_xpub);
344 case ZMQ_PAIR:
345 return strequals (type_, len_, socket_type_pair);
346 #ifdef ZMQ_BUILD_DRAFT_API
347 case ZMQ_SERVER:
348 return strequals (type_, len_, socket_type_client);
349 case ZMQ_CLIENT:
350 return strequals (type_, len_, socket_type_server);
351 case ZMQ_RADIO:
352 return strequals (type_, len_, socket_type_dish);
353 case ZMQ_DISH:
354 return strequals (type_, len_, socket_type_radio);
355 case ZMQ_GATHER:
356 return strequals (type_, len_, socket_type_scatter);
357 case ZMQ_SCATTER:
358 return strequals (type_, len_, socket_type_gather);
359 case ZMQ_DGRAM:
360 return strequals (type_, len_, socket_type_dgram);
361 case ZMQ_PEER:
362 return strequals (type_, len_, socket_type_peer);
363 case ZMQ_CHANNEL:
364 return strequals (type_, len_, socket_type_channel);
365 #endif
366 default:
367 break;
368 }
369 return false;
370 }
371