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