1 | /* |
2 | * Copyright Andrey Semashev 2007 - 2020. |
3 | * Distributed under the Boost Software License, Version 1.0. |
4 | * (See accompanying file LICENSE_1_0.txt or copy at |
5 | * http://www.boost.org/LICENSE_1_0.txt) |
6 | */ |
7 | /*! |
8 | * \file syslog_backend.cpp |
9 | * \author Andrey Semashev |
10 | * \date 08.01.2008 |
11 | * |
12 | * \brief This header is the Boost.Log library implementation, see the library documentation |
13 | * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. |
14 | */ |
15 | |
16 | #include <boost/log/detail/config.hpp> |
17 | |
18 | #ifndef BOOST_LOG_WITHOUT_SYSLOG |
19 | |
20 | #include <ctime> |
21 | #include <algorithm> |
22 | #include <stdexcept> |
23 | #include <boost/limits.hpp> |
24 | #include <boost/assert.hpp> |
25 | #include <boost/core/snprintf.hpp> |
26 | #include <boost/smart_ptr/weak_ptr.hpp> |
27 | #include <boost/smart_ptr/shared_ptr.hpp> |
28 | #include <boost/smart_ptr/make_shared_object.hpp> |
29 | #include <boost/throw_exception.hpp> |
30 | #if !defined(BOOST_LOG_NO_ASIO) |
31 | #include <boost/asio/buffer.hpp> |
32 | #include <boost/asio/socket_base.hpp> |
33 | #include <boost/asio/io_context.hpp> |
34 | #include <boost/asio/ip/udp.hpp> |
35 | #include <boost/asio/ip/address.hpp> |
36 | #include <boost/asio/ip/host_name.hpp> |
37 | #include <boost/asio/ip/resolver_base.hpp> |
38 | #endif |
39 | #include <boost/system/error_code.hpp> |
40 | #include <boost/date_time/c_time.hpp> |
41 | #include <boost/log/sinks/syslog_backend.hpp> |
42 | #include <boost/log/sinks/syslog_constants.hpp> |
43 | #include <boost/log/detail/singleton.hpp> |
44 | #include <boost/log/exceptions.hpp> |
45 | #if !defined(BOOST_LOG_NO_THREADS) |
46 | #include <boost/thread/locks.hpp> |
47 | #include <boost/thread/mutex.hpp> |
48 | #endif |
49 | #include "unique_ptr.hpp" |
50 | |
51 | #ifdef BOOST_LOG_USE_NATIVE_SYSLOG |
52 | #include <syslog.h> |
53 | #endif // BOOST_LOG_USE_NATIVE_SYSLOG |
54 | |
55 | #include <boost/log/detail/header.hpp> |
56 | |
57 | namespace boost { |
58 | |
59 | BOOST_LOG_OPEN_NAMESPACE |
60 | |
61 | namespace sinks { |
62 | |
63 | namespace syslog { |
64 | |
65 | //! The function constructs log record level from an integer |
66 | BOOST_LOG_API level make_level(int lev) |
67 | { |
68 | if (BOOST_UNLIKELY(static_cast< unsigned int >(lev) >= 8u)) |
69 | BOOST_THROW_EXCEPTION(std::out_of_range("syslog level value is out of range" )); |
70 | return static_cast< level >(lev); |
71 | } |
72 | |
73 | //! The function constructs log source facility from an integer |
74 | BOOST_LOG_API facility make_facility(int fac) |
75 | { |
76 | if (BOOST_UNLIKELY((static_cast< unsigned int >(fac) & 7u) != 0u |
77 | || static_cast< unsigned int >(fac) > (23u * 8u))) |
78 | { |
79 | BOOST_THROW_EXCEPTION(std::out_of_range("syslog facility code value is out of range" )); |
80 | } |
81 | return static_cast< facility >(fac); |
82 | } |
83 | |
84 | } // namespace syslog |
85 | |
86 | //////////////////////////////////////////////////////////////////////////////// |
87 | //! Syslog sink backend implementation |
88 | //////////////////////////////////////////////////////////////////////////////// |
89 | struct syslog_backend::implementation |
90 | { |
91 | #ifdef BOOST_LOG_USE_NATIVE_SYSLOG |
92 | struct native; |
93 | #endif // BOOST_LOG_USE_NATIVE_SYSLOG |
94 | #if !defined(BOOST_LOG_NO_ASIO) |
95 | struct udp_socket_based; |
96 | #endif |
97 | |
98 | //! Level mapper |
99 | severity_mapper_type m_LevelMapper; |
100 | |
101 | //! Logging facility (portable or native, depending on the backend implementation) |
102 | const int m_Facility; |
103 | |
104 | //! Constructor |
105 | explicit implementation(int facility) : |
106 | m_Facility(facility) |
107 | { |
108 | } |
109 | //! Virtual destructor |
110 | virtual ~implementation() {} |
111 | |
112 | //! The method sends the formatted message to the syslog host |
113 | virtual void send(syslog::level lev, string_type const& formatted_message) = 0; |
114 | }; |
115 | |
116 | |
117 | //////////////////////////////////////////////////////////////////////////////// |
118 | // Native syslog API support |
119 | //////////////////////////////////////////////////////////////////////////////// |
120 | |
121 | #ifdef BOOST_LOG_USE_NATIVE_SYSLOG |
122 | |
123 | BOOST_LOG_ANONYMOUS_NAMESPACE { |
124 | |
125 | //! Syslog service initializer (implemented as a weak singleton) |
126 | #if !defined(BOOST_LOG_NO_THREADS) |
127 | class native_syslog_initializer : |
128 | private log::aux::lazy_singleton< native_syslog_initializer, mutex > |
129 | #else |
130 | class native_syslog_initializer |
131 | #endif |
132 | { |
133 | #if !defined(BOOST_LOG_NO_THREADS) |
134 | friend class log::aux::lazy_singleton< native_syslog_initializer, mutex >; |
135 | typedef log::aux::lazy_singleton< native_syslog_initializer, mutex > mutex_holder; |
136 | #endif |
137 | |
138 | private: |
139 | /*! |
140 | * \brief Application identification string |
141 | * |
142 | * \note We have to keep it as an immutable member because some syslog implementations (e.g. glibc) |
143 | * do not deep-copy the ident string to internal storage when \c openlog is called |
144 | * and instead save a pointer to the user-provided string. This means the user-provided |
145 | * string needs to remain accessible for the whole duration of logging. |
146 | * |
147 | * https://github.com/boostorg/log/issues/97 |
148 | * https://sourceware.org/bugzilla/show_bug.cgi?id=25442 |
149 | */ |
150 | const std::string m_Ident; |
151 | |
152 | public: |
153 | native_syslog_initializer(std::string const& ident, int facility) : |
154 | m_Ident(ident) |
155 | { |
156 | ::openlog(ident: (m_Ident.empty() ? static_cast< const char* >(NULL) : m_Ident.c_str()), option: 0, facility: facility); |
157 | } |
158 | ~native_syslog_initializer() |
159 | { |
160 | ::closelog(); |
161 | } |
162 | |
163 | static shared_ptr< native_syslog_initializer > get_instance(std::string const& ident, int facility) |
164 | { |
165 | #if !defined(BOOST_LOG_NO_THREADS) |
166 | lock_guard< mutex > lock(mutex_holder::get()); |
167 | #endif |
168 | static weak_ptr< native_syslog_initializer > instance; |
169 | shared_ptr< native_syslog_initializer > p(instance.lock()); |
170 | if (!p) |
171 | { |
172 | p = boost::make_shared< native_syslog_initializer >(args: ident, args&: facility); |
173 | instance = p; |
174 | } |
175 | return p; |
176 | } |
177 | |
178 | BOOST_DELETED_FUNCTION(native_syslog_initializer(native_syslog_initializer const&)) |
179 | BOOST_DELETED_FUNCTION(native_syslog_initializer& operator= (native_syslog_initializer const&)) |
180 | }; |
181 | |
182 | } // namespace |
183 | |
184 | struct syslog_backend::implementation::native : |
185 | public implementation |
186 | { |
187 | //! Reference to the syslog service initializer |
188 | const shared_ptr< native_syslog_initializer > m_pSyslogInitializer; |
189 | |
190 | //! Constructor |
191 | native(syslog::facility const& fac, std::string const& ident) : |
192 | implementation(convert_facility(fac)), |
193 | m_pSyslogInitializer(native_syslog_initializer::get_instance(ident, facility: this->m_Facility)) |
194 | { |
195 | } |
196 | |
197 | //! The method sends the formatted message to the syslog host |
198 | void send(syslog::level lev, string_type const& formatted_message) BOOST_OVERRIDE |
199 | { |
200 | int native_level; |
201 | switch (lev) |
202 | { |
203 | case syslog::emergency: |
204 | native_level = LOG_EMERG; break; |
205 | case syslog::alert: |
206 | native_level = LOG_ALERT; break; |
207 | case syslog::critical: |
208 | native_level = LOG_CRIT; break; |
209 | case syslog::error: |
210 | native_level = LOG_ERR; break; |
211 | case syslog::warning: |
212 | native_level = LOG_WARNING; break; |
213 | case syslog::notice: |
214 | native_level = LOG_NOTICE; break; |
215 | case syslog::debug: |
216 | native_level = LOG_DEBUG; break; |
217 | default: |
218 | native_level = LOG_INFO; break; |
219 | } |
220 | |
221 | ::syslog(pri: this->m_Facility | native_level, fmt: "%s" , formatted_message.c_str()); |
222 | } |
223 | |
224 | private: |
225 | //! The function converts portable facility codes to the native codes |
226 | static int convert_facility(syslog::facility const& fac) |
227 | { |
228 | // POSIX does not specify anything except for LOG_USER and LOG_LOCAL* |
229 | #ifndef LOG_KERN |
230 | #define LOG_KERN LOG_USER |
231 | #endif |
232 | #ifndef LOG_DAEMON |
233 | #define LOG_DAEMON LOG_KERN |
234 | #endif |
235 | #ifndef LOG_MAIL |
236 | #define LOG_MAIL LOG_USER |
237 | #endif |
238 | #ifndef LOG_AUTH |
239 | #define LOG_AUTH LOG_DAEMON |
240 | #endif |
241 | #ifndef LOG_SYSLOG |
242 | #define LOG_SYSLOG LOG_DAEMON |
243 | #endif |
244 | #ifndef LOG_LPR |
245 | #define LOG_LPR LOG_DAEMON |
246 | #endif |
247 | #ifndef LOG_NEWS |
248 | #define LOG_NEWS LOG_USER |
249 | #endif |
250 | #ifndef LOG_UUCP |
251 | #define LOG_UUCP LOG_USER |
252 | #endif |
253 | #ifndef LOG_CRON |
254 | #define LOG_CRON LOG_DAEMON |
255 | #endif |
256 | #ifndef LOG_AUTHPRIV |
257 | #define LOG_AUTHPRIV LOG_AUTH |
258 | #endif |
259 | #ifndef LOG_FTP |
260 | #define LOG_FTP LOG_DAEMON |
261 | #endif |
262 | |
263 | static const int native_facilities[24] = |
264 | { |
265 | LOG_KERN, |
266 | LOG_USER, |
267 | LOG_MAIL, |
268 | LOG_DAEMON, |
269 | LOG_AUTH, |
270 | LOG_SYSLOG, |
271 | LOG_LPR, |
272 | LOG_NEWS, |
273 | LOG_UUCP, |
274 | LOG_CRON, |
275 | LOG_AUTHPRIV, |
276 | LOG_FTP, |
277 | |
278 | // reserved values |
279 | LOG_USER, |
280 | LOG_USER, |
281 | LOG_USER, |
282 | LOG_USER, |
283 | |
284 | LOG_LOCAL0, |
285 | LOG_LOCAL1, |
286 | LOG_LOCAL2, |
287 | LOG_LOCAL3, |
288 | LOG_LOCAL4, |
289 | LOG_LOCAL5, |
290 | LOG_LOCAL6, |
291 | LOG_LOCAL7 |
292 | }; |
293 | |
294 | std::size_t n = static_cast< unsigned int >(fac) / 8u; |
295 | BOOST_ASSERT(n < sizeof(native_facilities) / sizeof(*native_facilities)); |
296 | return native_facilities[n]; |
297 | } |
298 | }; |
299 | |
300 | #endif // BOOST_LOG_USE_NATIVE_SYSLOG |
301 | |
302 | |
303 | //////////////////////////////////////////////////////////////////////////////// |
304 | // Socket-based implementation |
305 | //////////////////////////////////////////////////////////////////////////////// |
306 | |
307 | #if !defined(BOOST_LOG_NO_ASIO) |
308 | |
309 | BOOST_LOG_ANONYMOUS_NAMESPACE { |
310 | |
311 | //! The shared UDP socket |
312 | struct syslog_udp_socket |
313 | { |
314 | private: |
315 | //! The socket primitive |
316 | asio::ip::udp::socket m_Socket; |
317 | |
318 | public: |
319 | //! The constructor creates a socket bound to the specified local address and port |
320 | explicit syslog_udp_socket(asio::io_context& io_ctx, asio::ip::udp const& protocol, asio::ip::udp::endpoint const& local_address) : |
321 | m_Socket(io_ctx) |
322 | { |
323 | m_Socket.open(protocol); |
324 | m_Socket.set_option(asio::socket_base::reuse_address(true)); |
325 | m_Socket.bind(endpoint: local_address); |
326 | } |
327 | //! The destructor closes the socket |
328 | ~syslog_udp_socket() |
329 | { |
330 | boost::system::error_code ec; |
331 | m_Socket.shutdown(what: asio::socket_base::shutdown_both, ec); |
332 | m_Socket.close(ec); |
333 | } |
334 | |
335 | //! The method sends the syslog message to the specified endpoint |
336 | void send_message(int pri, const char* local_host_name, asio::ip::udp::endpoint const& target, const char* message); |
337 | |
338 | BOOST_DELETED_FUNCTION(syslog_udp_socket(syslog_udp_socket const&)) |
339 | BOOST_DELETED_FUNCTION(syslog_udp_socket& operator= (syslog_udp_socket const&)) |
340 | }; |
341 | |
342 | //! The class contains the UDP service for syslog sockets to function |
343 | class syslog_udp_service : |
344 | public log::aux::lazy_singleton< syslog_udp_service, shared_ptr< syslog_udp_service > > |
345 | { |
346 | friend class log::aux::lazy_singleton< syslog_udp_service, shared_ptr< syslog_udp_service > >; |
347 | typedef log::aux::lazy_singleton< syslog_udp_service, shared_ptr< syslog_udp_service > > base_type; |
348 | |
349 | public: |
350 | //! The IO context instance |
351 | asio::io_context m_IOContext; |
352 | //! The local host name to put into log message |
353 | std::string m_LocalHostName; |
354 | |
355 | #if !defined(BOOST_LOG_NO_THREADS) |
356 | //! A synchronization primitive to protect the host name resolver |
357 | mutex m_Mutex; |
358 | //! The resolver is used to acquire connection endpoints |
359 | asio::ip::udp::resolver m_HostNameResolver; |
360 | #endif // !defined(BOOST_LOG_NO_THREADS) |
361 | |
362 | private: |
363 | //! Default constructor |
364 | syslog_udp_service() |
365 | #if !defined(BOOST_LOG_NO_THREADS) |
366 | : m_HostNameResolver(m_IOContext) |
367 | #endif // !defined(BOOST_LOG_NO_THREADS) |
368 | { |
369 | boost::system::error_code err; |
370 | m_LocalHostName = asio::ip::host_name(ec&: err); |
371 | } |
372 | //! Initializes the singleton instance |
373 | static void init_instance() |
374 | { |
375 | base_type::get_instance().reset(p: new syslog_udp_service()); |
376 | } |
377 | }; |
378 | |
379 | //! The method sends the syslog message to the specified endpoint |
380 | void syslog_udp_socket::send_message( |
381 | int pri, const char* local_host_name, asio::ip::udp::endpoint const& target, const char* message) |
382 | { |
383 | std::time_t t = std::time(NULL); |
384 | std::tm ts; |
385 | std::tm* time_stamp = boost::date_time::c_time::localtime(t: &t, result: &ts); |
386 | |
387 | // Month will have to be injected separately, as involving locale won't do here |
388 | static const char months[12][4] = |
389 | { |
390 | "Jan" , "Feb" , "Mar" , "Apr" , "May" , "Jun" , "Jul" , "Aug" , "Sep" , "Oct" , "Nov" , "Dec" |
391 | }; |
392 | |
393 | // The packet size is mandated in RFC3164, plus one for the terminating zero |
394 | char packet[1025]; |
395 | int n = boost::core::snprintf |
396 | ( |
397 | s: packet, |
398 | maxlen: sizeof(packet), |
399 | format: "<%d>%s %2d %02d:%02d:%02d %s %s" , |
400 | pri, |
401 | months[time_stamp->tm_mon], |
402 | time_stamp->tm_mday, |
403 | time_stamp->tm_hour, |
404 | time_stamp->tm_min, |
405 | time_stamp->tm_sec, |
406 | local_host_name, |
407 | message |
408 | ); |
409 | if (BOOST_LIKELY(n > 0)) |
410 | { |
411 | std::size_t packet_size = static_cast< std::size_t >(n) >= sizeof(packet) ? sizeof(packet) - 1u : static_cast< std::size_t >(n); |
412 | m_Socket.send_to(buffers: asio::buffer(data&: packet, max_size_in_bytes: packet_size), destination: target); |
413 | } |
414 | } |
415 | |
416 | } // namespace |
417 | |
418 | struct syslog_backend::implementation::udp_socket_based : |
419 | public implementation |
420 | { |
421 | //! Protocol to be used |
422 | asio::ip::udp m_Protocol; |
423 | //! Pointer to the list of sockets |
424 | shared_ptr< syslog_udp_service > m_pService; |
425 | //! Pointer to the socket being used |
426 | log::aux::unique_ptr< syslog_udp_socket > m_pSocket; |
427 | //! The target host to send packets to |
428 | asio::ip::udp::endpoint m_TargetHost; |
429 | |
430 | //! Constructor |
431 | explicit udp_socket_based(syslog::facility const& fac, asio::ip::udp const& protocol) : |
432 | implementation(fac), |
433 | m_Protocol(protocol), |
434 | m_pService(syslog_udp_service::get()) |
435 | { |
436 | if (m_Protocol == asio::ip::udp::v4()) |
437 | { |
438 | m_TargetHost = asio::ip::udp::endpoint(asio::ip::address_v4(0x7F000001), 514); // 127.0.0.1:514 |
439 | } |
440 | else |
441 | { |
442 | // ::1, port 514 |
443 | asio::ip::address_v6::bytes_type addr; |
444 | std::fill_n(first: addr.data(), n: addr.size() - 1u, value: static_cast< unsigned char >(0u)); |
445 | addr[addr.size() - 1u] = 1u; |
446 | m_TargetHost = asio::ip::udp::endpoint(asio::ip::address_v6(addr), 514); |
447 | } |
448 | } |
449 | |
450 | //! The method sends the formatted message to the syslog host |
451 | void send(syslog::level lev, string_type const& formatted_message) BOOST_OVERRIDE |
452 | { |
453 | if (!m_pSocket.get()) |
454 | { |
455 | asio::ip::udp::endpoint any_local_address(m_Protocol, 0u); |
456 | m_pSocket.reset(p: new syslog_udp_socket(m_pService->m_IOContext, m_Protocol, any_local_address)); |
457 | } |
458 | |
459 | m_pSocket->send_message( |
460 | pri: this->m_Facility | static_cast< int >(lev), |
461 | local_host_name: m_pService->m_LocalHostName.c_str(), |
462 | target: m_TargetHost, |
463 | message: formatted_message.c_str()); |
464 | } |
465 | }; |
466 | |
467 | #endif // !defined(BOOST_LOG_NO_ASIO) |
468 | |
469 | //////////////////////////////////////////////////////////////////////////////// |
470 | // Sink backend implementation |
471 | //////////////////////////////////////////////////////////////////////////////// |
472 | BOOST_LOG_API syslog_backend::syslog_backend() |
473 | { |
474 | construct(args: log::aux::empty_arg_list()); |
475 | } |
476 | |
477 | //! Destructor |
478 | BOOST_LOG_API syslog_backend::~syslog_backend() |
479 | { |
480 | delete m_pImpl; |
481 | } |
482 | |
483 | //! The method installs the function object that maps application severity levels to Syslog levels |
484 | BOOST_LOG_API void syslog_backend::set_severity_mapper(severity_mapper_type const& mapper) |
485 | { |
486 | m_pImpl->m_LevelMapper = mapper; |
487 | } |
488 | |
489 | //! The method writes the message to the sink |
490 | BOOST_LOG_API void syslog_backend::consume(record_view const& rec, string_type const& formatted_message) |
491 | { |
492 | m_pImpl->send( |
493 | lev: m_pImpl->m_LevelMapper.empty() ? syslog::info : m_pImpl->m_LevelMapper(rec), |
494 | formatted_message); |
495 | } |
496 | |
497 | |
498 | //! The method creates the backend implementation |
499 | BOOST_LOG_API void syslog_backend::construct(syslog::facility fac, syslog::impl_types use_impl, ip_versions ip_version, std::string const& ident) |
500 | { |
501 | #ifdef BOOST_LOG_USE_NATIVE_SYSLOG |
502 | if (use_impl == syslog::native) |
503 | { |
504 | typedef implementation::native native_impl; |
505 | m_pImpl = new native_impl(fac, ident); |
506 | return; |
507 | } |
508 | #endif // BOOST_LOG_USE_NATIVE_SYSLOG |
509 | |
510 | #if !defined(BOOST_LOG_NO_ASIO) |
511 | typedef implementation::udp_socket_based udp_socket_based_impl; |
512 | asio::ip::udp protocol = asio::ip::udp::v4(); |
513 | switch (ip_version) |
514 | { |
515 | case v4: |
516 | break; |
517 | case v6: |
518 | protocol = asio::ip::udp::v6(); |
519 | break; |
520 | default: |
521 | BOOST_LOG_THROW_DESCR(setup_error, "Incorrect IP version specified" ); |
522 | } |
523 | |
524 | m_pImpl = new udp_socket_based_impl(fac, protocol); |
525 | #endif |
526 | } |
527 | |
528 | #if !defined(BOOST_LOG_NO_ASIO) |
529 | |
530 | //! The method sets the local address which log records will be sent from. |
531 | BOOST_LOG_API void syslog_backend::set_local_address(std::string const& addr, unsigned short port) |
532 | { |
533 | #if !defined(BOOST_LOG_NO_THREADS) |
534 | typedef implementation::udp_socket_based udp_socket_based_impl; |
535 | if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) |
536 | { |
537 | char service_name[std::numeric_limits< unsigned int >::digits10 + 3]; |
538 | boost::core::snprintf(s: service_name, maxlen: sizeof(service_name), format: "%u" , static_cast< unsigned int >(port)); |
539 | |
540 | asio::ip::udp::endpoint local_address; |
541 | { |
542 | lock_guard< mutex > lock(impl->m_pService->m_Mutex); |
543 | asio::ip::udp::resolver::results_type results = impl->m_pService->m_HostNameResolver.resolve |
544 | ( |
545 | protocol: impl->m_Protocol, |
546 | host: addr, |
547 | service: service_name, |
548 | resolve_flags: asio::ip::resolver_base::address_configured | asio::ip::resolver_base::passive |
549 | ); |
550 | |
551 | local_address = *results.cbegin(); |
552 | } |
553 | |
554 | impl->m_pSocket.reset(p: new syslog_udp_socket(impl->m_pService->m_IOContext, impl->m_Protocol, local_address)); |
555 | } |
556 | #else |
557 | // Boost.ASIO requires threads for the host name resolver, |
558 | // so without threads we simply assume the string already contains IP address |
559 | set_local_address(boost::asio::ip::address::from_string(addr), port); |
560 | #endif // !defined(BOOST_LOG_NO_THREADS) |
561 | } |
562 | //! The method sets the local address which log records will be sent from. |
563 | BOOST_LOG_API void syslog_backend::set_local_address(boost::asio::ip::address const& addr, unsigned short port) |
564 | { |
565 | typedef implementation::udp_socket_based udp_socket_based_impl; |
566 | if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) |
567 | { |
568 | if ((impl->m_Protocol == asio::ip::udp::v4() && !addr.is_v4()) || (impl->m_Protocol == asio::ip::udp::v6() && !addr.is_v6())) |
569 | BOOST_LOG_THROW_DESCR(setup_error, "Incorrect IP version specified in the local address" ); |
570 | |
571 | impl->m_pSocket.reset(p: new syslog_udp_socket( |
572 | impl->m_pService->m_IOContext, impl->m_Protocol, asio::ip::udp::endpoint(addr, port))); |
573 | } |
574 | } |
575 | |
576 | //! The method sets the address of the remote host where log records will be sent to. |
577 | BOOST_LOG_API void syslog_backend::set_target_address(std::string const& addr, unsigned short port) |
578 | { |
579 | #if !defined(BOOST_LOG_NO_THREADS) |
580 | typedef implementation::udp_socket_based udp_socket_based_impl; |
581 | if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) |
582 | { |
583 | char service_name[std::numeric_limits< unsigned int >::digits10 + 3]; |
584 | boost::core::snprintf(s: service_name, maxlen: sizeof(service_name), format: "%u" , static_cast< unsigned int >(port)); |
585 | |
586 | asio::ip::udp::endpoint remote_address; |
587 | { |
588 | lock_guard< mutex > lock(impl->m_pService->m_Mutex); |
589 | asio::ip::udp::resolver::results_type results = impl->m_pService->m_HostNameResolver.resolve |
590 | ( |
591 | protocol: impl->m_Protocol, |
592 | host: addr, |
593 | service: service_name, |
594 | resolve_flags: asio::ip::resolver_query_base::address_configured |
595 | ); |
596 | |
597 | remote_address = *results.cbegin(); |
598 | } |
599 | |
600 | impl->m_TargetHost = remote_address; |
601 | } |
602 | #else |
603 | // Boost.ASIO requires threads for the host name resolver, |
604 | // so without threads we simply assume the string already contains IP address |
605 | set_target_address(boost::asio::ip::address::from_string(addr), port); |
606 | #endif // !defined(BOOST_LOG_NO_THREADS) |
607 | } |
608 | //! The method sets the address of the remote host where log records will be sent to. |
609 | BOOST_LOG_API void syslog_backend::set_target_address(boost::asio::ip::address const& addr, unsigned short port) |
610 | { |
611 | typedef implementation::udp_socket_based udp_socket_based_impl; |
612 | if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) |
613 | { |
614 | if ((impl->m_Protocol == asio::ip::udp::v4() && !addr.is_v4()) || (impl->m_Protocol == asio::ip::udp::v6() && !addr.is_v6())) |
615 | BOOST_LOG_THROW_DESCR(setup_error, "Incorrect IP version specified in the target address" ); |
616 | |
617 | impl->m_TargetHost = asio::ip::udp::endpoint(addr, port); |
618 | } |
619 | } |
620 | |
621 | #endif // !defined(BOOST_LOG_NO_ASIO) |
622 | |
623 | } // namespace sinks |
624 | |
625 | BOOST_LOG_CLOSE_NAMESPACE // namespace log |
626 | |
627 | } // namespace boost |
628 | |
629 | #include <boost/log/detail/footer.hpp> |
630 | |
631 | #endif // !defined(BOOST_LOG_WITHOUT_SYSLOG) |
632 | |