syslog_rs/
syslog_provider.rs

1/*-
2 * syslog-rs - a syslog client translated from libc to rust
3 * 
4 * Copyright 2025 Aleksandr Morozov
5 * 
6 * The syslog-rs crate can be redistributed and/or modified
7 * under the terms of either of the following licenses:
8 *
9 *   1. the Mozilla Public License Version 2.0 (the “MPL”) OR
10 *
11 *   2. The MIT License (MIT)
12 *                     
13 *   3. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
14 */
15
16use std::fmt;
17
18#[cfg(feature = "build_sync")]
19pub(super) use crate::sync::socket::{SyslogTap, Tap};
20
21#[cfg(feature = "async_enabled")]
22pub use crate::a_sync::{AsyncTap, AsyncSyslogTap};
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum DestinationType
26{
27    Local, Network, File
28}
29
30impl DestinationType
31{
32    #[inline]
33    pub 
34    fn is_network(&self) -> bool
35    {
36        return self == &Self::Network;
37    }
38}
39
40/// This trait is a common interface for the syslog realization which holds
41/// necessary info for compile time initialization and initialization during
42/// runtime.
43#[cfg(feature = "build_sync")]
44pub trait SyslogDestination: fmt::Debug + fmt::Display + Send + Clone + SyslogDestMsg + 'static
45{
46    /// A provider of the connection to syslog for sync code.
47    type SocketTap: SyslogTap<Self>;
48
49    const DEST_TYPE: DestinationType;
50}
51
52/// This trait is a common interface for the syslog realization which holds
53/// necessary info for compile time initialization and initialization during
54/// runtime. For async portion.
55#[cfg(feature = "async_enabled")]
56pub trait AsyncSyslogDestination: fmt::Debug + fmt::Display + Send + Clone + SyslogDestMsg + 'static
57{
58    /// A provider of the connection to syslog for async code.
59    type SocketTap: AsyncSyslogTap<Self>;
60}
61
62/// A commin trait for both sync and async which implements methods that 
63/// returns some specific values for each type of the `destination`.
64pub trait SyslogDestMsg: fmt::Debug + fmt::Display + Send + Clone + 'static
65{
66    /// Should return the max message length for specific syslog server type.
67    fn get_max_msg_len() -> usize;
68}
69
70
71/// A separate implementation of the `SyslogLocal` but for Windows. Due to the 
72/// complete incompat with the syslog methods, the implementation is separated.
73/// The user should use conditional compilation and have 2 static records i.e
74/// for target_family = "unix" and target_family = "windows".
75#[cfg(target_family = "windows")]
76pub mod imp_syslog_local
77{
78
79    use std::ffi::CString;
80
81    use crate::WINDOWS_EVENT_REPORT_MAX_PAYLOAD_LEN;
82    use crate::portable;
83    use crate::portable::EventLogLocal;
84
85    use crate::{error::SyRes, throw_error, map_error};
86
87    use super::*;
88
89    /// A local Event Log Windows only. But, even if you pick to log to Local Win 
90    /// event journal, you still need to create a special recs in the registry in order
91    /// to avoid the error.
92    /// 
93    /// @see [here](https://learn.microsoft.com/en-us/windows/win32/eventlog/reporting-an-event?redirectedfrom=MSDN)
94    /// for more information.
95    #[derive(Debug, Clone)]
96    pub struct WindowsEvent
97    {
98        /// A uniq name identifying the instance i.e like `MyName.MyComponent`.
99        service_name: CString,
100
101        /// Universal Naming Convention (UNC) name of the remote server on which this operation is to be performed.
102        unc_remote_server: Option<CString>,
103    }
104
105    impl fmt::Display for WindowsEvent
106    {
107        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
108        {
109            write!(f, "name: {}, guid: {}", 
110                unsafe { str::from_utf8_unchecked(self.service_name.as_bytes()) }, 
111                self.unc_remote_server.as_ref().map_or("NONE", |f|  unsafe { str::from_utf8_unchecked(f.as_bytes()) })
112            )
113        }
114    }
115
116    impl SyslogDestMsg for WindowsEvent
117    {
118        fn get_max_msg_len() -> usize 
119        {
120            return WINDOWS_EVENT_REPORT_MAX_PAYLOAD_LEN;
121        }
122    }
123
124    impl WindowsEvent
125    {
126        /// Creates a default connection to local event server. 
127        /// 
128        /// If the crate will not be
129        /// able to determine the program name, the "UnknownProgram" will be assigned.
130        pub 
131        fn new() -> Self
132        {
133            let service_name = 
134                portable::p_getprogname()
135                    .map(|v|
136                        {
137                            if v.is_empty() == true
138                            {
139                                "UnknownProgram".to_string()
140                            }
141                            else
142                            {
143                                v
144                            }
145                        }
146                    )
147                    .unwrap_or("UnknownProgram".to_string());
148
149            return
150                Self
151                {
152                    service_name: 
153                        CString::new(service_name).unwrap(),
154                    unc_remote_server: 
155                        None,
156                };
157        }
158
159        /// A custom instance init. 
160        /// 
161        /// If the crate will not be able to determine the program name, the 
162        /// "UnknownProgram" will be assigned.
163        /// 
164        /// # Arguments 
165        /// 
166        /// * `service_name` - an identification of the instance. This should be set
167        /// in order for the Event Server to find your instance in the registry.
168        /// 
169        /// * `unc_server` - a UNC to remote server.
170        /// 
171        /// # Returns
172        /// 
173        /// An error [Result::Err] will be returned if:
174        /// 
175        /// * `service_name` is empty string.
176        /// 
177        /// * `unc_server` - is [Option::Some] but empty string.
178        /// 
179        /// * [CString] failes to convert string to c-string for any reason.
180        pub 
181        fn new_custom(service_name: &str, unc_server: Option<&str>) -> SyRes<Self>
182        {
183            let service_name_cstr = 
184                if service_name.is_empty() == true
185                {
186                    throw_error!("service_name is empty");
187                }
188                else
189                {
190                    CString::new(service_name)
191                        .map_err(|e|
192                            map_error!("service_name CString error: '{}'", e)
193                        )?
194                };
195
196
197            let unc_serv_cstr = 
198                if let Some(unc) = unc_server
199                {
200                    if unc.is_empty() == true
201                    {
202                        throw_error!("service_name is empty");
203                    }
204
205                    Some(
206                        CString::new(unc)
207                            .map_err(|e|
208                            map_error!("service_name CString error: '{}'", e)
209                            )?
210                    )
211                }
212                else
213                {
214                    None
215                };
216
217            return Ok(
218                Self
219                {
220                    service_name: service_name_cstr,
221                    unc_remote_server: unc_serv_cstr
222                }
223            );
224        }
225
226        /// Returns the UNC to remote server if any.
227        #[inline]
228        pub 
229        fn get_server_unc(&self) -> Option<&CString>
230        {
231            return self.unc_remote_server.as_ref();
232        }
233
234        /// Returns the service name.
235        #[inline]
236        pub 
237        fn get_service_name(&self) -> &CString
238        {
239            return &self.service_name;
240        }
241    }
242
243    #[cfg(feature = "build_async_tokio")]
244    impl AsyncSyslogDestination for WindowsEvent
245    {
246        type SocketTap = AsyncTap::<EventLogLocal, Self>;
247
248    }
249
250    #[cfg(feature = "build_async_smol")]
251    impl AsyncSyslogDestination for WindowsEvent
252    {
253        type SocketTap = AsyncTap::<EventLogLocal, Self>;
254    }
255
256    #[cfg(feature = "build_sync")]
257    impl SyslogDestination for WindowsEvent
258    {
259        type SocketTap = Tap::<EventLogLocal, Self>;
260        
261        const DEST_TYPE: DestinationType = DestinationType::Local;
262    }
263}
264
265#[cfg(target_family = "windows")]
266pub use self::imp_syslog_local::WindowsEvent;
267
268#[cfg(target_family = "unix")]
269pub mod imp_syslog_local
270{
271    use std::{fmt, path::{Path, PathBuf}};
272
273    use crate::{common, error::SyRes, throw_error};
274    
275    use std::os::unix::net::UnixDatagram;
276    use super::*;
277
278    /// A local syslog which is working over datagram channel. If no path is specified,
279    /// it will try to find the syslog server by the hardcoded links. The same will be
280    /// performed if `use_alternative` is enabled when path is provided.
281    #[derive(Debug, Clone)]
282    pub struct SyslogLocal
283    {
284        /// A path to custom `UnixDatagram` socket.
285        custom_remote_path: Option<PathBuf>,
286
287        /// usefull only if `custom_path` is [Some]
288        use_alternative: bool,
289    }
290
291
292    impl fmt::Display for SyslogLocal
293    {
294        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
295        {
296            write!(f, "custom_path: {:?}, alt: {}", self.custom_remote_path, self.use_alternative)
297        }
298    }
299
300    impl SyslogLocal
301    {
302        fn new_internal(custom_path: Option<PathBuf>, use_alt_path: bool) -> SyRes<Self>
303        {
304            let remote_path: Option<PathBuf> = 
305                if let Some(path) = custom_path
306                {
307                    if use_alt_path == false
308                    {
309                        if path.exists() == false || path.is_file() == false
310                        {
311                            throw_error!("path either does not exists or not a file: '{}'", path.display());
312                        }
313                    }
314
315                    Some(path.to_path_buf())
316                }
317                else
318                {
319                    None
320                };
321
322            return Ok(
323                Self
324                { 
325                    custom_remote_path: remote_path, 
326                    use_alternative: use_alt_path, 
327                }
328            );
329        }
330
331        /// Creates a default connection to local syslog server. The correct path will be picked
332        /// automatically.
333        pub 
334        fn new() -> Self
335        {
336            return
337                Self::new_internal(None, false).unwrap();
338        }
339
340        /// Creates a special connection to specific local socket. If `use_alt_path` is 
341        /// set to true and `custom_path` is not available, other pre-programmed paths
342        /// will be probed and selected the first available.
343        pub 
344        fn new_custom_path<P: Into<PathBuf>>(custom_path: P, use_alt_path: bool) -> SyRes<Self>
345        {
346            return
347                Self::new_internal(Some(custom_path.into()), use_alt_path);
348        }
349
350        #[inline]
351        pub 
352        fn get_custom_remote_path(&self) -> Option<&Path>
353        {
354            return self.custom_remote_path.as_ref().map(|f| f.as_path());
355        }
356
357        #[inline]
358        pub 
359        fn get_use_alternative(&self) -> bool
360        {
361            return self.use_alternative;
362        }
363    }
364
365    impl SyslogDestMsg for SyslogLocal
366    {
367        fn get_max_msg_len() -> usize 
368        {
369            if *common::RFC5424_MAX_DGRAM >= common::MAXLINE
370            {
371                return common::MAXLINE;
372            }
373            else
374            {
375                return *common::RFC5424_MAX_DGRAM;
376            };
377        }
378    }
379
380    #[cfg(feature = "build_async_tokio")]
381    impl AsyncSyslogDestination for SyslogLocal
382    {
383        type SocketTap = AsyncTap::<tokio::net::UnixDatagram, Self>;
384
385    }
386
387    #[cfg(feature = "build_async_smol")]
388    impl AsyncSyslogDestination for SyslogLocal
389    {
390        type SocketTap = AsyncTap::<smol::net::unix::UnixDatagram, Self>;
391    }
392
393    #[cfg(feature = "build_sync")]
394    impl SyslogDestination for SyslogLocal
395    {
396        type SocketTap = Tap::<UnixDatagram, Self>;
397        
398        const DEST_TYPE: DestinationType = DestinationType::Local;
399    }
400}
401
402
403#[cfg(target_family = "unix")]
404pub use self::imp_syslog_local::SyslogLocal;
405
406#[cfg(feature = "build_ext_net")]
407pub mod imp_syslog_net
408{
409    use std::{fmt, net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream, UdpSocket}, time::Duration};
410
411    use crate::{common, error::SyRes, map_error, SyslogDestMsg};
412
413    use super::*;
414
415    /// A remote syslog server which works over plain TCP.
416    #[derive(Debug, Clone)]
417    pub struct SyslogNetTcp
418    {
419        /// Remote address in format host:port
420        remote_addr: SocketAddr,
421
422        /// Local bind address in format host:port.
423        bind_addr: SocketAddr,
424
425        /// A optional connection timeout.
426        conn_timeout: Option<Duration>
427    }
428
429    impl fmt::Display for SyslogNetTcp
430    {
431        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
432        {
433            write!(f, "remote_addr: {}, bind_addr: {}, conn_timeout: {:?}", self.remote_addr, 
434                self.bind_addr, self.conn_timeout)
435        }
436    }
437
438    impl SyslogNetTcp
439    {
440        /// Creates a new TCP connection to syslog server.
441        /// 
442        /// # Arguments
443        /// 
444        /// * `dest_addr` - a server's address in form "ip:port"
445        /// 
446        /// * `local` - a local bind address in format "ip:port". Optional.
447        ///     If not set, then will bind to 0.0.0.0 i.e OS specific.
448        /// 
449        /// * `conn_timeout` - an optional connection timeout. If not specified, then
450        ///     TCP connection timeout (OS specific).
451        pub 
452        fn new<P>(remote: P, local: Option<P>, conn_timeout: Option<Duration>) -> SyRes<Self>
453        where P: AsRef<str>
454        {
455            let remote_addr: SocketAddr = 
456                remote
457                    .as_ref()
458                    .parse()
459                    .map_err(|e| 
460                        map_error!("failed parsing remote addr '{}', error: '{}'", remote.as_ref(), e)
461                    )?;
462
463            let bind_addr: SocketAddr = 
464                if let Some(bind) = local
465                {
466                    bind
467                        .as_ref()
468                        .parse()
469                        .map_err(|e| 
470                            map_error!("failed parsing bind addr '{}', error: '{}'", remote.as_ref(), e)
471                        )?
472                }
473                else
474                {
475                    SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
476                };
477
478            return Ok(
479                Self
480                {
481                    remote_addr: remote_addr,
482                    bind_addr: bind_addr,
483                    conn_timeout: conn_timeout
484                }
485            );
486        }
487
488        #[inline]
489        pub 
490        fn get_remote_addr(&self) -> &SocketAddr
491        {
492            return &self.remote_addr;
493        }
494
495        #[inline]
496        pub 
497        fn get_bind_addr(&self) -> &SocketAddr
498        {
499            return &self.bind_addr;
500        }
501
502        #[inline]
503        pub 
504        fn get_conn_timeout(&self) -> Option<Duration>
505        {
506            return self.conn_timeout;
507        }
508    }
509
510    impl SyslogDestMsg for SyslogNetTcp
511    {
512        fn get_max_msg_len() -> usize 
513        {
514            return common::RFC5424_TCP_MAX_PKT_LEN;
515        }
516    }
517
518    #[cfg(feature = "build_async_tokio")]
519    impl AsyncSyslogDestination for SyslogNetTcp
520    {
521        type SocketTap = AsyncTap::<tokio::net::TcpStream, Self>;
522    }
523
524    #[cfg(feature = "build_async_smol")]
525    impl AsyncSyslogDestination for SyslogNetTcp
526    {
527        type SocketTap =  AsyncTap::<smol::net::TcpStream, Self>;
528    }
529
530    #[cfg(feature = "build_sync")]
531    impl SyslogDestination for SyslogNetTcp
532    {
533        type SocketTap = Tap::<TcpStream, Self>;
534
535        const DEST_TYPE: DestinationType = DestinationType::Network;
536    }
537
538
539    /// A remote syslog server which works over plain UDP.
540    #[derive(Debug, Clone)]
541    pub struct SyslogNetUdp
542    {
543        remote_addr: SocketAddr,
544        bind_addr: SocketAddr
545    }
546
547    impl fmt::Display for SyslogNetUdp
548    {
549        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
550        {
551            write!(f, "remote_addr: {}, bind_addr: {}", self.remote_addr, 
552                self.bind_addr)
553        }
554    }
555
556    impl SyslogNetUdp
557    {
558        /// Creates a new UDP connection to syslog server.
559        /// 
560        /// # Arguments
561        /// 
562        /// * `dest_addr` - a server's address in form "ip:port"
563        /// 
564        /// * `local` - a local bind address in format "ip:port". Optional.
565        ///     If not set, then will bind to 0.0.0.0 i.e OS specific.
566        pub 
567        fn new<P>(dest_addr: P, local: Option<P>) -> SyRes<Self>
568        where P: AsRef<str>
569        {
570            let remote_addr: SocketAddr = 
571                dest_addr
572                    .as_ref()
573                    .parse()
574                    .map_err(|e| 
575                        map_error!("failed parsing remote addr '{}', error: '{}'", dest_addr.as_ref(), e)
576                    )?;
577
578            let bind_addr: SocketAddr = 
579                if let Some(bind) = local
580                {
581                    bind
582                        .as_ref()
583                        .parse()
584                        .map_err(|e| 
585                            map_error!("failed parsing bind addr '{}', error: '{}'", dest_addr.as_ref(), e)
586                        )?
587                }
588                else
589                {
590                    SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
591                };
592
593            return Ok(
594                Self
595                {
596                    remote_addr: remote_addr,
597                    bind_addr: bind_addr
598                }
599            );
600        }
601
602        #[inline]
603        pub 
604        fn get_remote_addr(&self) -> &SocketAddr
605        {
606            return &self.remote_addr;
607        }
608
609        #[inline]
610        pub 
611        fn get_bind_addr(&self) -> &SocketAddr
612        {
613            return &self.bind_addr;
614        }
615    }
616
617    impl SyslogDestMsg for SyslogNetUdp
618    {
619        fn get_max_msg_len() -> usize 
620        {
621            return common::RFC5424_UDP_MAX_PKT_LEN;
622        }
623    }
624
625    #[cfg(feature = "build_async_tokio")]
626    impl AsyncSyslogDestination for SyslogNetUdp
627    {
628        type SocketTap = AsyncTap::<tokio::net::UdpSocket, Self>;
629    }
630
631    #[cfg(feature = "build_async_smol")]
632    impl AsyncSyslogDestination for SyslogNetUdp
633    {
634        type SocketTap = AsyncTap::<smol::net::UdpSocket, Self>;
635    }
636
637    #[cfg(feature = "build_sync")]
638    impl SyslogDestination for SyslogNetUdp
639    {
640        type SocketTap = Tap::<UdpSocket, Self>;
641
642        const DEST_TYPE: DestinationType = DestinationType::Network;
643    }
644}
645
646#[cfg(feature = "build_ext_net")]
647pub use self::imp_syslog_net::SyslogNetTcp;
648
649#[cfg(feature = "build_ext_net")]
650pub use self::imp_syslog_net::SyslogNetUdp;
651
652#[cfg(feature = "build_ext_file")]
653pub mod imp_syslog_file
654{
655    use std::{fmt, fs::File, path::{Path, PathBuf}};
656
657    use crate::{common};
658
659    use super::*;
660
661    /// A writer to local file. NO syslog server is required.
662    #[derive(Debug, Clone)]
663    pub struct SyslogFile
664    {
665        /// A path to text file on the file system.
666        file_path: PathBuf
667    }
668
669    impl fmt::Display for SyslogFile
670    {
671        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
672        {
673            write!(f, "<file> path: {}", self.file_path.display())
674        }
675    }
676
677    impl SyslogFile
678    {
679        /// Sets where to create or open file and write there.
680        pub 
681        fn new<P: Into<PathBuf>>(dest_path: P) -> Self
682        {
683            return
684                Self
685                {
686                    file_path: dest_path.into() 
687                };
688        }
689
690        #[inline]
691        pub 
692        fn get_path(&self) -> &Path
693        {
694            return self.file_path.as_path();
695        }
696    }
697
698    impl SyslogDestMsg for SyslogFile
699    {
700        fn get_max_msg_len() -> usize 
701        {
702            if *common::RFC5424_MAX_DGRAM >= common::MAXLINE
703            {
704                return common::MAXLINE;
705            }
706            else
707            {
708                return *common::RFC5424_MAX_DGRAM;
709            };
710        }
711    }
712
713    #[cfg(feature = "build_async_tokio")]
714    impl AsyncSyslogDestination for SyslogFile
715    {
716        type SocketTap = AsyncTap::<tokio::fs::File, Self>;
717    }
718
719    #[cfg(feature = "build_async_smol")]
720    impl AsyncSyslogDestination for SyslogFile
721    {
722        type SocketTap = AsyncTap::<smol::fs::File, Self>;
723    }
724
725    #[cfg(feature = "build_sync")]
726    impl SyslogDestination for SyslogFile
727    {
728        type SocketTap =  Tap::<File, Self>;
729
730        const DEST_TYPE: DestinationType = DestinationType::File;
731    }
732}
733
734#[cfg(feature = "build_ext_file")]
735pub use self::imp_syslog_file::SyslogFile;
736
737#[cfg(feature = "build_ext_tls")]
738pub mod imp_syslog_tls
739{
740    use std::fmt;
741    use std::{net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream}, sync::Arc, time::Duration};
742
743    #[cfg(feature = "build_sync")]
744use rustls::lock::Mutex;
745    use rustls::{pki_types::{CertificateDer, ServerName}, ClientConfig, ClientConnection, RootCertStore, StreamOwned};
746
747    use crate::{common, error::SyRes, map_error};
748
749    use super::*;
750
751    /// A remote syslog server with encrypted (TLS) over TCP connection.
752    #[derive(Debug, Clone)]
753    pub struct SyslogTls
754    {
755        /// A remote address in format host:port.
756        remote_addr: SocketAddr,
757
758        /// A local address to bind in format host:port.
759        bind_addr: SocketAddr,
760
761        /// A remote server name.
762        serv_name: ServerName<'static>,
763
764        /// A pre-configuret config.
765        client_config: Arc<ClientConfig>,
766
767        /// An optional connection time out. If not specified, OS (TCP) default.
768        conn_timeout: Option<Duration>,
769    }
770
771    impl fmt::Display for SyslogTls
772    {
773        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
774        {
775            write!(f, "remote: {}, bind: {}, serv_name: {:?}, client: {:?}, conn_timeout: {:?}", self.remote_addr, 
776                self.bind_addr, self.serv_name, self.client_config, self.conn_timeout)
777        }
778    }
779
780    impl SyslogTls
781    {
782        /// Creates a new TLS over TCP connection to syslog server. 
783        /// 
784        /// # Arguments
785        /// 
786        /// * `remote` - an (ip:port) to specific server.
787        /// 
788        /// * `local` - an (ip:port) to local bind address. Optional. If not set,
789        ///     OS specific behaviour.
790        /// 
791        /// * `serv_name` - a FQDN of server (should match with `root_cert`)
792        /// 
793        /// * `root_cert` - root certificates able to provide a root-of-trust for connection authentication.
794        /// 
795        /// * `conn_timeout` - an optional connection timeout. If not specified, will be OS (TCP) connection
796        ///     timeout default.
797        pub 
798        fn new<P>(remote: P, local: Option<P>, serv_name: impl Into<String>, 
799            root_cert: Vec<u8>, conn_timeout: Option<Duration>) -> SyRes<Self>
800        where P: AsRef<str>
801        {
802            use rustls::pki_types::pem::PemObject;
803
804            let server_name = serv_name.into();
805
806            let remote_addr: SocketAddr = 
807                remote
808                    .as_ref()
809                    .parse()
810                    .map_err(|e| 
811                        map_error!("failed parsing remote addr '{}', error: '{}'", remote.as_ref(), e)
812                    )?;
813
814            let cert = 
815                CertificateDer::from_pem_slice(root_cert.as_slice())
816                    .map_err(|e|
817                        map_error!("certificate parse error: '{}'", e)
818                    )?;
819
820            let mut root_store = RootCertStore::empty();
821            root_store
822                .add(cert)
823                .map_err(|e|
824                    map_error!("can not add root ceritficate, error: '{}'", e)
825                )?;
826
827            let serv_name = 
828                server_name
829                    .try_into()
830                    .map_err(|e|
831                        map_error!("server name error: '{}'", e)
832                    )?;
833
834            let client_config = 
835                rustls::ClientConfig::builder()
836                    .with_root_certificates(root_store)
837                    .with_no_client_auth();
838
839            let bind_addr: SocketAddr = 
840                if let Some(bind) = local
841                {
842                    bind
843                        .as_ref()
844                        .parse()
845                        .map_err(|e| 
846                            map_error!("failed parsing bind addr '{}', error: '{}'", remote.as_ref(), e)
847                        )?
848                }
849                else
850                {
851                    SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
852                };
853
854            return Ok(
855                Self
856                {
857                    remote_addr: remote_addr, 
858                    bind_addr: bind_addr,
859                    serv_name: serv_name,
860                    client_config: Arc::new(client_config),
861                    conn_timeout: conn_timeout,
862                }
863            );
864        }
865
866        #[inline]
867        pub
868        fn get_remote_addr(&self) -> &SocketAddr
869        {
870            return &self.remote_addr;
871        }
872
873        #[inline]
874        pub 
875        fn get_bind_addr(&self) -> &SocketAddr
876        {
877            return &self.bind_addr;
878        }
879
880        #[inline]
881        pub 
882        fn get_serv_name(&self) -> ServerName<'static>
883        {
884            return self.serv_name.clone();
885        }
886
887        #[inline]
888        pub 
889        fn get_client_config(&self) -> Arc<ClientConfig>
890        {
891            return self.client_config.clone();
892        }
893
894        #[inline]
895        pub 
896        fn get_get_conn_timeout(&self) -> Option<Duration>
897        {
898            return self.conn_timeout.clone();
899        }
900    }
901
902    impl SyslogDestMsg for SyslogTls
903    {
904        fn get_max_msg_len() -> usize 
905        {
906             return common::RFC5424_TCP_MAX_PKT_LEN;
907        }
908    }
909
910    #[cfg(feature = "build_async_tokio")]
911    impl AsyncSyslogDestination for SyslogTls
912    {
913        type SocketTap = AsyncTap::<tokio_rustls::client::TlsStream<tokio::net::TcpStream>, Self>;
914    }
915
916    #[cfg(feature = "build_async_smol")]
917    impl AsyncSyslogDestination for SyslogTls
918    {
919        type SocketTap = AsyncTap::<futures_rustls::client::TlsStream<smol::net::TcpStream>, Self>;
920    }
921
922    #[cfg(feature = "build_sync")]
923    impl SyslogDestination for SyslogTls
924    {
925        type SocketTap = Tap::<Mutex<StreamOwned<ClientConnection, TcpStream>>, Self>;
926
927        const DEST_TYPE: DestinationType = DestinationType::Network;
928    }
929}
930
931#[cfg(feature = "build_ext_tls")]
932pub use self::imp_syslog_tls::SyslogTls;