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
41zmq::mechanism_t::mechanism_t (const options_t &options_) : options (options_)
42{
43}
44
45zmq::mechanism_t::~mechanism_t ()
46{
47}
48
49void 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
55void 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
63void 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
71const zmq::blob_t &zmq::mechanism_t::get_user_id () const
72{
73 return _user_id;
74}
75
76const char socket_type_pair[] = "PAIR";
77const char socket_type_pub[] = "PUB";
78const char socket_type_sub[] = "SUB";
79const char socket_type_req[] = "REQ";
80const char socket_type_rep[] = "REP";
81const char socket_type_dealer[] = "DEALER";
82const char socket_type_router[] = "ROUTER";
83const char socket_type_pull[] = "PULL";
84const char socket_type_push[] = "PUSH";
85const char socket_type_xpub[] = "XPUB";
86const char socket_type_xsub[] = "XSUB";
87const char socket_type_stream[] = "STREAM";
88#ifdef ZMQ_BUILD_DRAFT_API
89const char socket_type_server[] = "SERVER";
90const char socket_type_client[] = "CLIENT";
91const char socket_type_radio[] = "RADIO";
92const char socket_type_dish[] = "DISH";
93const char socket_type_gather[] = "GATHER";
94const char socket_type_scatter[] = "SCATTER";
95const char socket_type_dgram[] = "DGRAM";
96#endif
97
98const char *zmq::mechanism_t::socket_type_string (int socket_type_) const
99{
100 // TODO the order must of the names must correspond to the values resp. order of ZMQ_* socket type definitions in zmq.h!
101 static const char *names[] = {
102 socket_type_pair, socket_type_pub, socket_type_sub,
103 socket_type_req, socket_type_rep, socket_type_dealer,
104 socket_type_router, socket_type_pull, socket_type_push,
105 socket_type_xpub, socket_type_xsub, socket_type_stream,
106#ifdef ZMQ_BUILD_DRAFT_API
107 socket_type_server, socket_type_client, socket_type_radio,
108 socket_type_dish, socket_type_gather, socket_type_scatter,
109 socket_type_dgram
110#endif
111 };
112 static const size_t names_count = sizeof (names) / sizeof (names[0]);
113 zmq_assert (socket_type_ >= 0 && socket_type_ < (int) names_count);
114 return names[socket_type_];
115}
116
117const size_t name_len_size = sizeof (unsigned char);
118const size_t value_len_size = sizeof (uint32_t);
119
120static size_t property_len (size_t name_len_, size_t value_len_)
121{
122 return name_len_size + name_len_ + value_len_size + value_len_;
123}
124
125static size_t name_len (const char *name_)
126{
127 const size_t name_len = strlen (name_);
128 zmq_assert (name_len <= UCHAR_MAX);
129 return name_len;
130}
131
132size_t zmq::mechanism_t::add_property (unsigned char *ptr_,
133 size_t ptr_capacity_,
134 const char *name_,
135 const void *value_,
136 size_t value_len_)
137{
138 const size_t name_len = ::name_len (name_);
139 const size_t total_len = ::property_len (name_len, value_len_);
140 zmq_assert (total_len <= ptr_capacity_);
141
142 *ptr_ = static_cast<unsigned char> (name_len);
143 ptr_ += name_len_size;
144 memcpy (ptr_, name_, name_len);
145 ptr_ += name_len;
146 zmq_assert (value_len_ <= 0x7FFFFFFF);
147 put_uint32 (ptr_, static_cast<uint32_t> (value_len_));
148 ptr_ += value_len_size;
149 memcpy (ptr_, value_, value_len_);
150
151 return total_len;
152}
153
154size_t zmq::mechanism_t::property_len (const char *name_, size_t value_len_)
155{
156 return ::property_len (name_len (name_), value_len_);
157}
158
159#define ZMTP_PROPERTY_SOCKET_TYPE "Socket-Type"
160#define ZMTP_PROPERTY_IDENTITY "Identity"
161
162size_t zmq::mechanism_t::add_basic_properties (unsigned char *ptr_,
163 size_t ptr_capacity_) const
164{
165 unsigned char *ptr = ptr_;
166
167 // Add socket type property
168 const char *socket_type = socket_type_string (options.type);
169 ptr += add_property (ptr, ptr_capacity_, ZMTP_PROPERTY_SOCKET_TYPE,
170 socket_type, strlen (socket_type));
171
172 // Add identity (aka routing id) property
173 if (options.type == ZMQ_REQ || options.type == ZMQ_DEALER
174 || options.type == ZMQ_ROUTER) {
175 ptr += add_property (ptr, ptr_capacity_ - (ptr - ptr_),
176 ZMTP_PROPERTY_IDENTITY, options.routing_id,
177 options.routing_id_size);
178 }
179
180
181 for (std::map<std::string, std::string>::const_iterator
182 it = options.app_metadata.begin (),
183 end = options.app_metadata.end ();
184 it != end; ++it) {
185 ptr +=
186 add_property (ptr, ptr_capacity_ - (ptr - ptr_), it->first.c_str (),
187 it->second.c_str (), strlen (it->second.c_str ()));
188 }
189
190 return ptr - ptr_;
191}
192
193size_t zmq::mechanism_t::basic_properties_len () const
194{
195 const char *socket_type = socket_type_string (options.type);
196 size_t meta_len = 0;
197
198 for (std::map<std::string, std::string>::const_iterator
199 it = options.app_metadata.begin (),
200 end = options.app_metadata.end ();
201 it != end; ++it) {
202 meta_len +=
203 property_len (it->first.c_str (), strlen (it->second.c_str ()));
204 }
205
206 return property_len (ZMTP_PROPERTY_SOCKET_TYPE, strlen (socket_type))
207 + meta_len
208 + ((options.type == ZMQ_REQ || options.type == ZMQ_DEALER
209 || options.type == ZMQ_ROUTER)
210 ? property_len (ZMTP_PROPERTY_IDENTITY, options.routing_id_size)
211 : 0);
212}
213
214void zmq::mechanism_t::make_command_with_basic_properties (
215 msg_t *msg_, const char *prefix_, size_t prefix_len_) const
216{
217 const size_t command_size = prefix_len_ + basic_properties_len ();
218 const int rc = msg_->init_size (command_size);
219 errno_assert (rc == 0);
220
221 unsigned char *ptr = static_cast<unsigned char *> (msg_->data ());
222
223 // Add prefix
224 memcpy (ptr, prefix_, prefix_len_);
225 ptr += prefix_len_;
226
227 add_basic_properties (
228 ptr, command_size - (ptr - static_cast<unsigned char *> (msg_->data ())));
229}
230
231int zmq::mechanism_t::parse_metadata (const unsigned char *ptr_,
232 size_t length_,
233 bool zap_flag_)
234{
235 size_t bytes_left = length_;
236
237 while (bytes_left > 1) {
238 const size_t name_length = static_cast<size_t> (*ptr_);
239 ptr_ += name_len_size;
240 bytes_left -= name_len_size;
241 if (bytes_left < name_length)
242 break;
243
244 const std::string name =
245 std::string (reinterpret_cast<const char *> (ptr_), name_length);
246 ptr_ += name_length;
247 bytes_left -= name_length;
248 if (bytes_left < value_len_size)
249 break;
250
251 const size_t value_length = static_cast<size_t> (get_uint32 (ptr_));
252 ptr_ += value_len_size;
253 bytes_left -= value_len_size;
254 if (bytes_left < value_length)
255 break;
256
257 const uint8_t *value = ptr_;
258 ptr_ += value_length;
259 bytes_left -= value_length;
260
261 if (name == ZMTP_PROPERTY_IDENTITY && options.recv_routing_id)
262 set_peer_routing_id (value, value_length);
263 else if (name == ZMTP_PROPERTY_SOCKET_TYPE) {
264 if (!check_socket_type (reinterpret_cast<const char *> (value),
265 value_length)) {
266 errno = EINVAL;
267 return -1;
268 }
269 } else {
270 const int rc = property (name, value, value_length);
271 if (rc == -1)
272 return -1;
273 }
274 (zap_flag_ ? _zap_properties : _zmtp_properties)
275 .ZMQ_MAP_INSERT_OR_EMPLACE (
276 name,
277 std::string (reinterpret_cast<const char *> (value), value_length));
278 }
279 if (bytes_left > 0) {
280 errno = EPROTO;
281 return -1;
282 }
283 return 0;
284}
285
286int zmq::mechanism_t::property (const std::string & /* name_ */,
287 const void * /* value_ */,
288 size_t /* length_ */)
289{
290 // Default implementation does not check
291 // property values and returns 0 to signal success.
292 return 0;
293}
294
295template <size_t N>
296static bool strequals (const char *actual_type_,
297 const size_t actual_len_,
298 const char (&expected_type_)[N])
299{
300 return actual_len_ == N - 1
301 && memcmp (actual_type_, expected_type_, N - 1) == 0;
302}
303
304bool zmq::mechanism_t::check_socket_type (const char *type_,
305 const size_t len_) const
306{
307 switch (options.type) {
308 case ZMQ_REQ:
309 return strequals (type_, len_, socket_type_rep)
310 || strequals (type_, len_, socket_type_router);
311 case ZMQ_REP:
312 return strequals (type_, len_, socket_type_req)
313 || strequals (type_, len_, socket_type_dealer);
314 case ZMQ_DEALER:
315 return strequals (type_, len_, socket_type_rep)
316 || strequals (type_, len_, socket_type_dealer)
317 || strequals (type_, len_, socket_type_router);
318 case ZMQ_ROUTER:
319 return strequals (type_, len_, socket_type_req)
320 || strequals (type_, len_, socket_type_dealer)
321 || strequals (type_, len_, socket_type_router);
322 case ZMQ_PUSH:
323 return strequals (type_, len_, socket_type_pull);
324 case ZMQ_PULL:
325 return strequals (type_, len_, socket_type_push);
326 case ZMQ_PUB:
327 return strequals (type_, len_, socket_type_sub)
328 || strequals (type_, len_, socket_type_xsub);
329 case ZMQ_SUB:
330 return strequals (type_, len_, socket_type_pub)
331 || strequals (type_, len_, socket_type_xpub);
332 case ZMQ_XPUB:
333 return strequals (type_, len_, socket_type_sub)
334 || strequals (type_, len_, socket_type_xsub);
335 case ZMQ_XSUB:
336 return strequals (type_, len_, socket_type_pub)
337 || strequals (type_, len_, socket_type_xpub);
338 case ZMQ_PAIR:
339 return strequals (type_, len_, socket_type_pair);
340#ifdef ZMQ_BUILD_DRAFT_API
341 case ZMQ_SERVER:
342 return strequals (type_, len_, socket_type_client);
343 case ZMQ_CLIENT:
344 return strequals (type_, len_, socket_type_server);
345 case ZMQ_RADIO:
346 return strequals (type_, len_, socket_type_dish);
347 case ZMQ_DISH:
348 return strequals (type_, len_, socket_type_radio);
349 case ZMQ_GATHER:
350 return strequals (type_, len_, socket_type_scatter);
351 case ZMQ_SCATTER:
352 return strequals (type_, len_, socket_type_gather);
353 case ZMQ_DGRAM:
354 return strequals (type_, len_, socket_type_dgram);
355#endif
356 default:
357 break;
358 }
359 return false;
360}
361