Line data Source code
1 : // Snap Communicator -- classes to ease handling communication between processes
2 : // Copyright (c) 2012-2019 Made to Order Software Corp. All Rights Reserved
3 : //
4 : // This program is free software; you can redistribute it and/or modify
5 : // it under the terms of the GNU General Public License as published by
6 : // the Free Software Foundation; either version 2 of the License, or
7 : // (at your option) any later version.
8 : //
9 : // This program is distributed in the hope that it will be useful,
10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : // GNU General Public License for more details.
13 : //
14 : // You should have received a copy of the GNU General Public License
15 : // along with this program; if not, write to the Free Software
16 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 :
18 : /** \file
19 : * \brief Implementation of the Connection with Send Message class.
20 : *
21 : * This is a base class which ease the implementation of a connection
22 : * which is able to send and receive messages.
23 : */
24 :
25 :
26 : // self
27 : //
28 : #include "eventdispatcher/connection_with_send_message.h"
29 :
30 : #include "eventdispatcher/dispatcher_support.h"
31 : #include "eventdispatcher/exception.h"
32 :
33 :
34 : // snaplogger lib
35 : //
36 : #include "snaplogger/logger.h"
37 : #include "snaplogger/message.h"
38 :
39 :
40 : // snapdev lib
41 : //
42 : //#include "snapdev/not_reached.h"
43 : #include "snapdev/not_used.h"
44 : //#include "snapdev/string_replace_many.h"
45 :
46 :
47 : // boost lib
48 : //
49 : #include <boost/algorithm/string/join.hpp>
50 :
51 :
52 : //// libaddr lib
53 : ////
54 : //#include "libaddr/addr_parser.h"
55 : //
56 : //
57 : //// C++ lib
58 : ////
59 : //#include <sstream>
60 : //#include <limits>
61 : //#include <atomic>
62 : //
63 : //
64 : //// C lib
65 : ////
66 : //#include <fcntl.h>
67 : //#include <poll.h>
68 : //#include <unistd.h>
69 : //#include <sys/eventfd.h>
70 : //#include <sys/inotify.h>
71 : //#include <sys/ioctl.h>
72 : //#include <sys/resource.h>
73 : //#include <sys/syscall.h>
74 : //#include <sys/time.h>
75 :
76 :
77 : // last include
78 : //
79 : #include <snapdev/poison.h>
80 :
81 :
82 :
83 :
84 : namespace ed
85 : {
86 :
87 :
88 :
89 : /** \brief Initialize a connection_with_send_message object.
90 : *
91 : * This constructor initializes a connectopm which supports a send_message()
92 : * function. This allows that object to send a certain number of default
93 : * messages such as the UNKNOWN message automatically.
94 : */
95 0 : connection_with_send_message::~connection_with_send_message()
96 : {
97 0 : }
98 :
99 :
100 :
101 : /** \brief Build the HELP reply and send it.
102 : *
103 : * When a daemon registers with the snapcommunicator, it sends a REGISTER
104 : * command. As a result, the daemon is sent a HELP command which must be
105 : * answered with a COMMAND and the list of commands that this connection
106 : * supports.
107 : *
108 : * \note
109 : * If the environment logger is not currently configured, this message
110 : * gets ignored.
111 : *
112 : * \param[in] message The HELP message.
113 : *
114 : * \sa msg_ready()
115 : */
116 0 : void connection_with_send_message::msg_help(message & msg)
117 : {
118 0 : snap::NOTUSED(msg);
119 :
120 0 : bool need_user_help(true);
121 0 : string_list_t commands;
122 :
123 : dispatcher_base * d;
124 0 : dispatcher_support * ds(dynamic_cast<dispatcher_support *>(this));
125 0 : if(ds != nullptr)
126 : {
127 : // we extract the bare pointer because in the other case
128 : // we only get a bare pointer... (which we can't safely
129 : // put in a shared pointer, although we could attempt to
130 : // use shared_from_this() but we could have a class without
131 : // it?)
132 : //
133 0 : d = ds->get_dispatcher().get();
134 : }
135 : else
136 : {
137 0 : d = dynamic_cast<dispatcher_base *>(this);
138 : }
139 0 : if(d != nullptr)
140 : {
141 0 : need_user_help = d->get_commands(commands);
142 : }
143 :
144 : // the user has "unknown" commands (as far as the dispatcher is concerned)
145 : // in his list of commands so we have to let him enter them "manually"
146 : //
147 : // this happens whenever there is an entry which is a regular expression
148 : // or something similar which we just cannot grab
149 : //
150 0 : if(need_user_help)
151 : {
152 0 : help(commands);
153 : }
154 :
155 : // the list of commands just cannot be empty
156 : //
157 0 : if(commands.empty())
158 : {
159 : throw event_dispatcher_implementation_error(
160 : "connection_with_send_message::msg_help()"
161 0 : " is not able to determine the commands this messenger supports");
162 : }
163 :
164 : // Now prepare the COMMAND message and send it
165 : //
166 : // Note: we turn off the caching on this message, it does not make sense
167 : // because if snapcommunicator is not running, then caching won't
168 : // happen work anyway (i.e. snapcommunicator has to send HELP first
169 : // and then we send the reply, if it has to restart, then just
170 : // sending COMMANDS will fail.)
171 : //
172 0 : message reply;
173 0 : reply.set_command("COMMANDS");
174 0 : reply.add_parameter("list", boost::algorithm::join(commands, ","));
175 0 : if(!send_message(reply, false))
176 : {
177 : SNAP_LOG_WARNING
178 0 : << "could not reply to \""
179 0 : << msg.get_command()
180 0 : << "\" with a COMMANDS message.";
181 : }
182 0 : }
183 :
184 :
185 : /** \brief Reply to the watchdog message ALIVE.
186 : *
187 : * To check whether a service is alive, send the ALIVE message. This
188 : * function builds a ABSOLUTELY reply and attaches the "serial" parameter
189 : * as is if present. It will also include the original "timestamp" parameter
190 : * when present.
191 : *
192 : * The function also adds one field named "reply_timestamp" with the Unix
193 : * time when the reply is being sent.
194 : *
195 : * \note
196 : * The "serial" parameter is expected to be used to make sure that no messages
197 : * are lost, or if loss is expected, to see whether loss is heavy or not.
198 : *
199 : * \note
200 : * The "serial" and "timestamp" parameters do not get checked. If present
201 : * in the original message, they get copied verbatim to the destination.
202 : * This allows you to include anything you want in those parameters although
203 : * we suggest you use the "timestamp" only for a value representing time.
204 : *
205 : * \param[in] message The STOP message.
206 : */
207 0 : void connection_with_send_message::msg_alive(message & msg)
208 : {
209 0 : message absolutely;
210 0 : absolutely.reply_to(msg);
211 0 : absolutely.set_command("ABSOLUTELY");
212 0 : if(msg.has_parameter("serial"))
213 : {
214 0 : absolutely.add_parameter("serial", msg.get_parameter("serial"));
215 : }
216 0 : if(msg.has_parameter("timestamp"))
217 : {
218 0 : absolutely.add_parameter("timestamp", msg.get_parameter("timestamp"));
219 : }
220 0 : absolutely.add_parameter("reply_timestamp", time(nullptr));
221 0 : if(!send_message(absolutely, false))
222 : {
223 : SNAP_LOG_WARNING
224 0 : << "could not reply to \""
225 0 : << msg.get_command()
226 0 : << "\" with an ABSOLULTELY message.";
227 : }
228 0 : }
229 :
230 :
231 : /** \brief Reconfigure the logger.
232 : *
233 : * Whenever the logrotate runs or some changes are maed to the log
234 : * definitions, the corresponding daemons need to reconfigure their
235 : * logger to make use of the new file and settings. This command is
236 : * used for the purpose.
237 : *
238 : * \note
239 : * If the environment logger is not currently configured, this message
240 : * gets ignored.
241 : *
242 : * \param[in] message The STOP message.
243 : */
244 0 : void connection_with_send_message::msg_log(message & msg)
245 : {
246 0 : snap::NOTUSED(msg);
247 :
248 0 : if(snaplogger::is_configured())
249 : {
250 : // send log in the old file and format
251 : //
252 : SNAP_LOG_INFO
253 0 : << "-------------------- Logging reconfiguration request.";
254 :
255 : // reconfigure
256 : //
257 0 : snaplogger::reopen();
258 :
259 : // send log to new file and format
260 : //
261 : SNAP_LOG_INFO
262 0 : << "-------------------- Logging reconfiguration done.";
263 : }
264 0 : }
265 :
266 :
267 : /** \brief Call you stop() function with true.
268 : *
269 : * This command means that someone is asking your daemon to quit as soon as
270 : * possible because the Snap! environment is being asked to shutdown.
271 : *
272 : * The value 'true' means that all the daemons are being asked to stop and
273 : * not just you.
274 : *
275 : * \param[in] message The STOP message.
276 : *
277 : * \sa msg_stop()
278 : */
279 0 : void connection_with_send_message::msg_quitting(message & msg)
280 : {
281 0 : snap::NOTUSED(msg);
282 :
283 0 : stop(true);
284 0 : }
285 :
286 :
287 : /** \brief Call you ready() function with the message.
288 : *
289 : * All daemons using the snapcommunicator daemon have to have a ready()
290 : * function which gets called once the HELP and COMMAND message were
291 : * handled. This is why your daemon is expected to be ready to start
292 : * working. Some daemon, though, start working immediately no matter
293 : * what (i.e. snapwatchdog and snapfirewall do work either way.)
294 : *
295 : * \param[in] message The READY message.
296 : *
297 : * \sa msg_help()
298 : */
299 0 : void connection_with_send_message::msg_ready(message & msg)
300 : {
301 : // pass the message so any additional info can be accessed.
302 : //
303 0 : ready(msg);
304 0 : }
305 :
306 :
307 : /** \brief Call you stop() function with false.
308 : *
309 : * This command means that someone is asking your daemon to stop.
310 : *
311 : * The value 'false' means just your daemon was asked to stop and not the
312 : * entire system to shutdown (otherwise you would receive a QUITTING command
313 : * instead.)
314 : *
315 : * \param[in] message The STOP message.
316 : *
317 : * \sa msg_quitting()
318 : */
319 0 : void connection_with_send_message::msg_stop(message & msg)
320 : {
321 0 : snap::NOTUSED(msg);
322 :
323 0 : stop(false);
324 0 : }
325 :
326 :
327 : /** \brief Handle the UNKNOWN message.
328 : *
329 : * Whenever we send a command to another daemon, that command can be refused
330 : * by sending an UNKNOWN reply. This function handles the UNKNOWN command
331 : * by simply recording that as an error in the logs.
332 : *
333 : * \param[in] message The UNKNOWN message we just received.
334 : */
335 0 : void connection_with_send_message::msg_log_unknown(message & msg)
336 : {
337 : // we sent a command that the other end did not understand
338 : // and got an UNKNOWN reply
339 : //
340 : SNAP_LOG_ERROR
341 0 : << "we sent unknown command \""
342 0 : << msg.get_parameter("command")
343 0 : << "\" and probably did not get the expected result.";
344 0 : }
345 :
346 :
347 : /** \brief Send the UNKNOWN message as a reply.
348 : *
349 : * This function replies to the \p message with the UNKNOWN message as
350 : * expected by all our `snap_connection`'s when a service receives a
351 : * message it does not know how to handle.
352 : *
353 : * It is expected to be used in your dispatcher_match array.
354 : *
355 : * \note
356 : * This function is virtual which allows you to add it to your array of
357 : * of dispatcher_match items. The following shows an example of what that
358 : * can look like.
359 : *
360 : * \code
361 : * {
362 : * ...
363 : *
364 : * // ALWAYS LAST
365 : * {
366 : * nullptr
367 : * , &my_service_connection::msg_reply_with_unknown
368 : * , &snap::dispatcher<my_service_connection>::dispatcher_match::always_match
369 : * }
370 : * };
371 : * \endcode
372 : *
373 : * \param[in] message The messageto reply to.
374 : */
375 0 : void connection_with_send_message::msg_reply_with_unknown(message & msg)
376 : {
377 0 : message unknown;
378 0 : unknown.reply_to(msg);
379 0 : unknown.set_command("UNKNOWN");
380 0 : unknown.add_parameter("command", msg.get_command());
381 0 : if(!send_message(unknown, false))
382 : {
383 : SNAP_LOG_WARNING
384 0 : << "could not reply to \""
385 0 : << msg.get_command()
386 0 : << "\" with UNKNOWN message.";
387 : }
388 0 : }
389 :
390 :
391 : /** \brief The default help() function does nothing.
392 : *
393 : * This implementation does nothing. It is expected that you reimplement
394 : * this function depending on your daemon's need.
395 : *
396 : * The help() function gets called whenever the list of commands can't be
397 : * 100% defined automatically.
398 : *
399 : * Your function is expected to add commands to the \p commands parameter
400 : * as in:
401 : *
402 : * \code
403 : * commands << "MSG1";
404 : * commands << "MSG2";
405 : * commands << "MSG3";
406 : * \endcode
407 : *
408 : * This allows you to handle those three messages with a single entry in
409 : * your list of dispatcher_match objects with a regular expression such
410 : * as "MSG[1-3]".
411 : *
412 : * \param[in,out] commands List of commands to update.
413 : */
414 0 : void connection_with_send_message::help(string_list_t & commands)
415 : {
416 0 : snap::NOTUSED(commands);
417 :
418 : // do nothing by default -- user is expected to overload this function
419 0 : }
420 :
421 :
422 : /** \brief The default ready() function does nothing.
423 : *
424 : * This implementation does nothing. It is expected that you reimplement
425 : * this function depending on your daemon's need. Most often this function
426 : * is the one that really starts your daemons process.
427 : *
428 : * \param[in,out] message The READY message.
429 : */
430 0 : void connection_with_send_message::ready(message & msg)
431 : {
432 0 : snap::NOTUSED(msg);
433 :
434 : // do nothing by default -- user is expected to overload this function
435 : //
436 : SNAP_LOG_WARNING
437 0 : << "default ready() function was called.";
438 0 : }
439 :
440 :
441 : /** \brief The default stop() function does nothing.
442 : *
443 : * This implementation does nothing. It is expected that you reimplement
444 : * this function depending on your daemon's need.
445 : *
446 : * \param[in] quitting Whether the QUITTING (true) or STOP (false) command
447 : * was received.
448 : */
449 0 : void connection_with_send_message::stop(bool quitting)
450 : {
451 0 : snap::NOTUSED(quitting);
452 :
453 : // do nothing by default -- user is expected to overload this function
454 : //
455 : SNAP_LOG_WARNING
456 0 : << "default stop() function was called.";
457 0 : }
458 :
459 :
460 :
461 6 : } // namespace ed
462 : // vim: ts=4 sw=4 et
|