Turi Create  4.0
message_types.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef CPPIPC_COMMON_MESSAGE_TYPES_HPP
7 #define CPPIPC_COMMON_MESSAGE_TYPES_HPP
8 #include <string>
9 #include <exception>
10 #include <sstream>
11 #include <map>
12 #include <core/system/nanosockets/zmq_msg_vector.hpp>
13 #include <typeinfo>
14 #include <core/system/exceptions/error_types.hpp>
15 #include <core/export.hpp>
16 namespace cppipc {
17 namespace nanosockets = turi::nanosockets;
18 /**
19  * \ingroup cppipc
20  * The contents of the message used to call a function from
21  * the client to the server.
22  */
23 struct EXPORT call_message {
24  /// Default constructor
25  call_message(): objectid(0), body(NULL), zmqbodyused(false) {}
26  /**
27  * constructs a call_message from a zmq_msg_vector.
28  * Will also, as a side effect, clear the zmq_msg_vector.
29  * Any existing contents in the call_message will be cleared.
30  * Returns true on success, false if the format is incorrect.
31  */
32  bool construct(nanosockets::zmq_msg_vector& vec);
33 
34  /**
35  * appends the message a zmq_msg_vector from a call message.
36  * Will also as a side effect, clear the contents of this call message.
37  */
38  void emit(nanosockets::zmq_msg_vector& vec);
39 
40  /// Empties the message, freeing all contents
41  void clear();
42 
43  ~call_message(){clear();};
44 
45  size_t objectid; /// the object to call
46  std::string function_name; /// the function to call on the object
47  std::map<std::string, std::string> properties; /// Other properties
48 
49  nanosockets::nn_msg_t bodybuf; /** When receiving, this will contain the actual contents
50  of the body */
51  const char* body; /// The serialized arguments of the call. May point into bodybuf
52  size_t bodylen; /// The length of the body.
53 
54  /*
55  * The need to have the seperate zmqbodybuf is that zeromq messages are
56  * "intelligent". If they are small, they are managed in place inside
57  * the nn_msg_t directly. Only if they are big, then a malloc is used.
58  * However, zeromq does not provide me an easy way to figure out when this is
59  * the case, and I would like to maintain the zero-copy behavior of the
60  * messages as much as possible. The solution is therefore to use zmq_msg_move
61  * to move the the body contents into a new nn_msg_t, then take pointers
62  * into that.
63  *
64  * zmqbodyused should only be set on receiving. i.e. by the construct
65  * call.
66  */
67  bool zmqbodyused; /// True if bodybuf is used and body is from bodybuf
68 
69  private:
70  call_message(const call_message&);
71  call_message& operator=(const call_message&);
72 };
73 
74 
75 /**
76  * \ingroup cppipc
77  * The reply status.
78  */
79 enum class reply_status:size_t {
80  OK, ///< Call was successful
81  BAD_MESSAGE, ///< The object requested did not exist
82  NO_OBJECT, ///< The object requested did not exist
83  NO_FUNCTION, ///< The function requested did not exist
84  COMM_FAILURE, ///< Communication error
85  AUTH_FAILURE, ///< Authentication failure
86  IO_ERROR, ///< IO Error
87  MEMORY_ERROR, ///< Memory Error
88  INDEX_ERROR, ///< Index Error
89  TYPE_ERROR, ///< Type Error
90  EXCEPTION, ///< Other general exception. Body will contain the exception message.
91 };
92 
93 
94 /**
95  * \ingroup cppipc
96  * The contents of the message when replying from the server to the client.
97  */
98 struct EXPORT reply_message {
99  /// Default constructor
100  reply_message(): body(NULL), bodylen(0),zmqbodyused(false) {}
101  /**
102  * Constructs a reply_message from a zmq_msg_vector.
103  * Will also, as a side effect, clear the zmq_msg_vector
104  * Any existing contents in the reply_message will be cleared;
105  * Returns true on success, false if the format is incorrect.
106  */
107  bool construct(nanosockets::zmq_msg_vector& vec);
108 
109  /**
110  * appends the message a zmq_msg_vector from a call message.
111  * Will also as a side effect, clear the contents of this call message.
112  */
113  void emit(nanosockets::zmq_msg_vector& vec);
114 
115  /// Empties the message, freeing all contents
116  void clear();
117 
118  ~reply_message(){clear();};
119 
120  reply_status status; /// The status of the call.
121  std::map<std::string, std::string> properties; /// Other properties
122  nanosockets::nn_msg_t bodybuf; /** When receiving, this will contain the actual contents
123  of the body */
124  char* body; /// The serialized contents of the reply. May point into bodybuf
125  size_t bodylen; /// The length of the body.
126 
127  /*
128  * The need to have the seperate zmqbodybuf is that zeromq messages are
129  * "intelligent". If they are small, they are managed in place inside
130  * the nn_msg_t directly. Only if they are big, then a malloc is used.
131  * However, zeromq does not provide me an easy way to figure out when this is
132  * the case, and I would like to maintain the zero-copy behavior of the
133  * messages as much as possible. The solution is therefore to use zmq_msg_move
134  * to move the the body contents into a new nn_msg_t, then take pointers
135  * into that.
136  *
137  * zmqbodyused should only be set on receiving. i.e. by the construct
138  * call.
139  */
140  bool zmqbodyused; /// True if bodybuf is used and body is from bodybuf
141 
142  inline void copy_body_from(const std::string& s) {
143  assert(zmqbodyused == false);
144  if (!body) free(body);
145  body = (char*)malloc(s.length());
146  memcpy(body, s.c_str(), s.length());
147  bodylen = s.length();
148  }
149 
150  inline void copy_body_from(const char* c, size_t len) {
151  assert(zmqbodyused == false);
152  if (!body) free(body);
153  body = (char*)malloc(len);
154  memcpy(body, c, len);
155  bodylen = len;
156  }
157  private:
159  reply_message& operator=(const reply_message&);
160 };
161 
162 
163 /**
164  * \ingroup cppipc
165  * Generates a printable string version of the a reply_status
166  */
168 
169 class ipcexception : public std::exception {
170  public:
171  ipcexception(reply_status s,
172  std::string custom_errstring = "")
173  :status(s), errorcode(0), custom_errstring(custom_errstring) {
174  make_error_string();
175  }
176  ipcexception(reply_status s,
177  int errorcode,
178  std::string custom_errstring = "")
179  :status(s), errorcode(errorcode), custom_errstring(custom_errstring){
180  make_error_string();
181  }
182 
183  virtual ~ipcexception() throw() { }
184 
185  const char* what() const throw() {
186  return errstring.c_str();
187  }
188 
189  /**
190  * Returns the reply_status value
191  */
192  reply_status get_reply_status() {
193  return status;
194  }
195 
196  /**
197  * Returns the zeroMQ error code which caused the error. If any.
198  */
199  int get_zeromq_errorcode() {
200  return errorcode;
201  }
202 
203  private:
204  reply_status status;
205  int errorcode;
206  std::string errstring;
207  std::string custom_errstring;
208 
209  void make_error_string() {
210  std::stringstream strm;
211  if (errorcode == 0) {
212  strm << reply_status_to_string(status)
213  << ". " << custom_errstring;
214  } else {
215  strm << reply_status_to_string(status) + ": " << errorcode
216  << ". " << custom_errstring;
217  }
218  strm.flush();
219  errstring = strm.str();
220  }
221 };
222 
223 } // cppipc
224 #endif
Authentication failure.
Other general exception. Body will contain the exception message.
std::map< std::string, std::string > properties
The status of the call.
std::string nn_msg_t
nanosockets::nn_msg_t bodybuf
Other properties.
call_message()
Default constructor.
std::string function_name
the object to call
The object requested did not exist.
nanosockets::nn_msg_t bodybuf
Other properties.
Call was successful.
reply_message()
Default constructor.
std::string reply_status_to_string(reply_status)
The object requested did not exist.
The function requested did not exist.
std::map< std::string, std::string > properties
the function to call on the object
size_t bodylen
The serialized arguments of the call. May point into bodybuf.
void copy_body_from(const std::string &s)
True if bodybuf is used and body is from bodybuf.
bool zmqbodyused
The length of the body.
bool zmqbodyused
The length of the body.
size_t bodylen
The serialized contents of the reply. May point into bodybuf.