Line data Source code
1 : // Copyright (c) 2020-2021 Made to Order Software Corp.
2 : // All rights reserved
3 : //
4 : // https://snapwebsites.org/project/eventdispatcher
5 : // contact@m2osw.com
6 : //
7 : // This program is free software; you can redistribute it and/or modify
8 : // it under the terms of the GNU General Public License as published by
9 : // the Free Software Foundation; either version 2 of the License, or
10 : // (at your option) any later version.
11 : //
12 : // This program is distributed in the hope that it will be useful,
13 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : // GNU General Public License for more details.
16 : //
17 : // You should have received a copy of the GNU General Public License
18 : // along with this program; if not, write to the Free Software
19 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 :
21 : // self
22 : //
23 : #include "eventdispatcher/logrotate_udp_messenger.h"
24 :
25 :
26 : // addr lib
27 : //
28 : #include <libaddr/addr_parser.h>
29 :
30 :
31 : // last include
32 : //
33 : #include <snapdev/poison.h>
34 :
35 :
36 :
37 : namespace ed
38 : {
39 :
40 :
41 :
42 : /** \brief The UDP server initialization.
43 : *
44 : * The UDP server creates a new UDP server to listen on incoming
45 : * messages over a UDP connection.
46 : *
47 : * This UDP implementation is used to listen to the LOG message specifically.
48 : * It is often that you want to restart the snaplogger and this can be used
49 : * as the way to do it. The UDP message can be sent using the ed-signal
50 : * command line tool:
51 : *
52 : * \code
53 : * ed-signal --server 127.0.0.1:1234 --message LOG --type udp
54 : * \endcode
55 : *
56 : * The reaction of the server is to restart the snaplogger as implemented in
57 : * the default dispatcher messages (see the messages.cpp for details).
58 : *
59 : * If you already have a UDP service in your application, you can simply
60 : * add the default dispatcher messages and the LOG message will automatically
61 : * be handled for you. No need to create yet another network connection.
62 : * We do so in this constructor like so:
63 : *
64 : * \code
65 : * f_dispatcher->add_communicator_commands();
66 : * \endcode
67 : *
68 : * \param[in] addr The address/port to listen on. Most often it is the private
69 : * address (127.0.0.1).
70 : * \param[in] secret_code A secret code to verify in order to accept UDP
71 : * messages.
72 : */
73 0 : logrotate_udp_messenger::logrotate_udp_messenger(
74 : addr::addr const & address
75 0 : , std::string const & secret_code)
76 0 : : ed::udp_server_message_connection(address.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS), address.get_port())
77 : , f_dispatcher(std::make_shared<ed::dispatcher<logrotate_udp_messenger>>(
78 : this
79 0 : , ed::dispatcher<logrotate_udp_messenger>::dispatcher_match::vector_t()))
80 : {
81 0 : set_name("logrotate_udp_messenger");
82 0 : set_secret_code(secret_code);
83 0 : f_dispatcher->add_communicator_commands();
84 : #ifdef _DEBUG
85 0 : f_dispatcher->set_trace();
86 : #endif
87 0 : set_dispatcher(f_dispatcher);
88 0 : }
89 :
90 :
91 : /** \brief The logrotate messenger destructor.
92 : *
93 : * This function is here because the logrotate_udp_messenger derives from
94 : * classes that have virtual functions and the destructor of such classes
95 : * have to be defined virtual.
96 : */
97 0 : logrotate_udp_messenger::~logrotate_udp_messenger()
98 : {
99 0 : }
100 :
101 :
102 : /** \brief Implement a send message for it is required.
103 : *
104 : * This function does nothing. It has to be defined because one of the
105 : * dependencies of this class has a pure virtual function named send_message().
106 : *
107 : * In a later implementation we may change this implementation.
108 : *
109 : * \param[in] msg The message to be sent (ignored).
110 : * \param[in] cache Whether to cache the message if it can't immediately be
111 : * sent (ignored).
112 : *
113 : * \return Always returns true (as if the message was sent successfully).
114 : */
115 0 : bool logrotate_udp_messenger::send_message(ed::message const & msg, bool cache)
116 : {
117 0 : snap::NOT_USED(msg, cache);
118 0 : return true;
119 : }
120 :
121 :
122 :
123 : namespace
124 : {
125 :
126 :
127 : /** \brief Options to handle the logrotate UDP IP:port.
128 : *
129 : */
130 : advgetopt::option const g_options[] =
131 : {
132 : // LOGROTATE OPTIONS
133 : //
134 : advgetopt::define_option(
135 : advgetopt::Name("logrotate-listen")
136 : , advgetopt::ShortName(U'R')
137 : , advgetopt::Flags(advgetopt::all_flags<
138 : advgetopt::GETOPT_FLAG_GROUP_OPTIONS
139 : , advgetopt::GETOPT_FLAG_COMMAND_LINE
140 : , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE
141 : , advgetopt::GETOPT_FLAG_CONFIGURATION_FILE
142 : , advgetopt::GETOPT_FLAG_REQUIRED>())
143 : , advgetopt::Help("the host and port to listen on for `LOG` messages.")
144 : ),
145 : advgetopt::define_option(
146 : advgetopt::Name("logrotate-secret")
147 : , advgetopt::Flags(advgetopt::all_flags<
148 : advgetopt::GETOPT_FLAG_GROUP_OPTIONS
149 : , advgetopt::GETOPT_FLAG_COMMAND_LINE
150 : , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE
151 : , advgetopt::GETOPT_FLAG_CONFIGURATION_FILE
152 : , advgetopt::GETOPT_FLAG_REQUIRED>())
153 : , advgetopt::DefaultValue("")
154 : , advgetopt::Help("a secret code to be used along the logrotate-listen option; use empty (the default) to not have to use a secret code.")
155 : ),
156 :
157 : // END
158 : //
159 : advgetopt::end_options()
160 : };
161 :
162 : } // no name namespace
163 :
164 :
165 :
166 0 : logrotate_extension::logrotate_extension(
167 : advgetopt::getopt & opts
168 : , std::string const & default_address
169 0 : , int default_port)
170 : : f_opts(opts)
171 : , f_default_address(default_address)
172 0 : , f_default_port(default_port)
173 : {
174 0 : }
175 :
176 :
177 0 : void logrotate_extension::add_logrotate_options()
178 : {
179 : // add options
180 : //
181 0 : f_opts.parse_options_info(g_options, true);
182 :
183 : // add the default of the --logrotate-listen option manually so it can
184 : // be dynamic
185 : //
186 0 : advgetopt::option_info::pointer_t o(f_opts.get_option("logrotate-listen"));
187 0 : if(o == nullptr)
188 : {
189 0 : SNAP_LOG_ERROR
190 0 : << "somehow the \"--logrotate-listen\" option was not added and we can't find it."
191 : << SNAP_LOG_SEND;
192 0 : return;
193 : }
194 :
195 0 : if(!f_default_address.empty())
196 : {
197 0 : if(f_default_port > 0)
198 : {
199 0 : o->set_default(f_default_address + ':' + std::to_string(f_default_port));
200 : }
201 : else
202 : {
203 0 : o->set_default(f_default_address);
204 : }
205 : }
206 0 : else if(f_default_port > 0)
207 : {
208 : // TODO: make sure this works, otherwise use 127.0.0.1 as the default IP
209 : //
210 0 : o->set_default(':' + std::to_string(f_default_port));
211 : }
212 :
213 : }
214 :
215 :
216 : /** \brief Call this function after you finalized option processing.
217 : *
218 : * This function act on the logrotate various command line options.
219 : * Assuming the command line options were valid, this function will
220 : * open a UDP port which will listen for `LOG` messages . On such
221 : * a message, it will trigger a reopening of any file the logger
222 : * is dealing with.
223 : *
224 : * Once you are ready to quit your process, make sure to call the
225 : * disconnect_logrotate_messenger() function to remove this logrotate
226 : * extension from the communicator. Not doing so would block the
227 : * communicator since it would continue to listen for `LOG` messages.
228 : */
229 0 : void logrotate_extension::process_logrotate_options()
230 : {
231 0 : addr::addr const logrotate_addr(addr::string_to_addr(
232 0 : f_opts.get_string("logrotate-listen")
233 : , f_default_address
234 : , f_default_port
235 0 : , "udp"));
236 :
237 0 : f_logrotate_messenger = std::make_shared<ed::logrotate_udp_messenger>(
238 : logrotate_addr
239 0 : , f_opts.get_string("logrotate-secret"));
240 :
241 0 : ed::communicator::instance()->add_connection(f_logrotate_messenger);
242 0 : }
243 :
244 :
245 : /** \brief Remove the logrotate UDP messenger from the communicator.
246 : *
247 : * Once you are ready to quit, make sure to remove the UDP messenger from
248 : * the communicator by calling this function. You can safely call this
249 : * function multiple times. You can also call this function early (before
250 : * quitting), just keep in mind that means you won't get your logs rotated
251 : * anymore if you do so too early.
252 : */
253 0 : void logrotate_extension::disconnect_logrotate_messenger()
254 : {
255 0 : ed::communicator::instance()->remove_connection(f_logrotate_messenger);
256 0 : f_logrotate_messenger.reset();
257 0 : }
258 :
259 :
260 :
261 6 : } // namespace ed
262 : // vim: ts=4 sw=4 et
|