cdns_rs/a_sync/
network.rs

1/*-
2 * cdns-rs - a simple sync/async DNS query library
3 * 
4 * Copyright (C) 2020  Aleksandr Morozov
5 * 
6 * Copyright (C) 2025  Aleksandr Morozov
7 * 
8 * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
9 * the European Commission - subsequent versions of the EUPL (the "Licence").
10 * 
11 * You may not use this work except in compliance with the Licence.
12 * 
13 * You may obtain a copy of the Licence at:
14 * 
15 *    https://joinup.ec.europa.eu/software/page/eupl
16 * 
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
19 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
20 * Licence for the specific language governing permissions and limitations
21 * under the Licence.
22 */
23
24use std::fmt;
25use std::marker::PhantomData;
26use std::net::SocketAddr;
27use std::os::fd::{AsFd, BorrowedFd};
28use std::sync::Arc;
29use std::time::Duration;
30use core::fmt::Debug;
31
32use async_trait::async_trait;
33
34//use rustls::pki_types::ServerName;
35
36use crate::cfg_resolv_parser::ResolveConfEntry;
37use crate::network_common::SocketTapCommon;
38
39use crate::error::*;
40
41/// A common interface to access the realizations for both [TcpStream] and
42/// [UdpSocket]
43#[async_trait]
44#[allow(async_fn_in_trait)]
45pub trait SocketTap<LOC>: SocketTapCommon + Send + Sync + fmt::Debug
46{
47    /// Connects to the remote host.  
48    async fn connect(&mut self, conn_timeout: Option<Duration>) -> CDnsResult<()>;
49
50    /// Tells if current instace is `encrypted` i.e [TcpTlsConnection] over [TcpStream].
51    fn is_encrypted(&self) -> bool;
52
53    /// Tells if current instance is [TcpStream] if true, or [UdpSocket] if false
54    fn is_tcp(&self) -> bool;
55
56    fn should_append_len(&self) -> bool;
57
58    async fn poll_read(&self) -> CDnsResult<()>;
59
60    /// Sends data over wire.  
61    async fn send(&mut self, sndbuf: &[u8]) -> CDnsResult<usize> ;
62
63    /// Receives data transmitted from remote host.
64    /// In nonblocking mode it should be called only after the event was polled
65    /// In blocking mode it will block until received or timeout.
66    async fn recv(&mut self, rcvbuf: &mut [u8]) -> CDnsResult<usize>;
67}
68
69
70pub type NetworkTapType<LOC> = (dyn SocketTap<LOC> + Send + Sync);
71
72pub trait SocketTaps<LOC>: Clone + fmt::Debug + Send + Sync
73{
74    type TcpSock: AsFd;
75    type UdpSock: AsFd;
76
77    #[cfg(feature = "use_async_tls")]
78    type TlsSock: AsFd;
79    /*type LocalDatagramSock: AsFd;
80    type LocalStreamSock: AsFd;*/
81
82    fn new_tcp_socket(resolver: Arc<ResolveConfEntry>, timeout: Duration) -> CDnsResult<Box<NetworkTapType<LOC>>>;
83    fn new_udp_socket(resolver: Arc<ResolveConfEntry>, timeout: Duration) -> CDnsResult<Box<NetworkTapType<LOC>>>;
84
85    #[cfg(feature = "use_async_tls")]
86    fn new_tls_socket(resolver: Arc<ResolveConfEntry>, timeout: Duration) -> CDnsResult<Box<NetworkTapType<LOC>>>;
87    /*fn new_local_dgram_socket(resolver: Arc<ResolveConfEntry>, timeout: Duration) -> NetworkTap<Self::LocalDatagramSock>;
88    fn new_local_stream_socket(resolver: Arc<ResolveConfEntry>, timeout: Duration) -> NetworkTap<Self::LocalStreamSock>;*/
89}
90
91
92
93
94/// An instance of the socket/stream.
95pub struct NetworkTap<T: AsFd, LOC>
96{
97    /// Channel
98    pub sock: Option<T>, 
99    /// Receive timeout
100    pub timeout: Duration,
101    /// Instance's config
102    pub cfg: Arc<ResolveConfEntry>,
103
104    pub _loc: PhantomData<LOC>,
105}
106
107unsafe impl<T: AsFd, LOC> Send for NetworkTap<T, LOC> {}
108unsafe impl<T: AsFd, LOC> Sync for NetworkTap<T, LOC> {}
109
110impl<T: AsFd + Debug, LOC> fmt::Debug for NetworkTap<T, LOC>
111{
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
113    {
114        f.debug_struct("NetworkTap").field("sock", &self.sock).field("timeout", &self.timeout).field("cfg", &self.cfg).finish()
115    }
116}
117
118impl<T: AsFd, LOC> NetworkTap<T, LOC>
119{
120    /// Creates new instance of network which is 'tapped' with [SocketTap]. 
121    /// A socket is not initially connected and `SocketTap::connect` should be called.
122    /// 
123    /// # Arguments
124    /// 
125    /// * `resolver_ip` - a ref to [IpAddr] which holds host address of the nameserver.
126    /// 
127    /// * `resolver_port` - a port number binded by nameserver
128    /// 
129    /// * `bind_addr` - a local address to bind the socket to
130    /// 
131    /// # Returns
132    /// 
133    /// * [CDnsResult] - Ok with inner type [Box] dyn [SocketTap]
134    /// 
135    /// * [CDnsResult] - Err with error description
136    pub 
137    fn new(resolver: Arc<ResolveConfEntry>, timeout: Duration) -> CDnsResult<Box<NetworkTapType<LOC>>> where NetworkTap<T, LOC>: SocketTap<LOC> + 'static
138    {
139        /*let domain_name = 
140            if let Some(domainname) = resolver.get_tls_domain()
141            {
142                webpki::DnsNameRef::try_from_ascii_str(domainname).map_err(|e| internal_error_map!(CDnsErrorType::InternalError, "{}", e))?
143                //ServerName::try_from(domainname.clone()).map_err(|e| internal_error_map!(CDnsErrorType::InternalError, "{}", e))?
144            }
145            else
146            {
147                internal_error!(CDnsErrorType::InternalError, "no domain is set for TLS conncection");
148            };
149*/
150        let ret = 
151            NetworkTap::<T, LOC>
152            { 
153                sock: None, 
154               // domain_name: domain_name,
155                timeout: timeout,
156                cfg: resolver,
157                _loc: PhantomData
158            };
159
160        return Ok( Box::new(ret) );
161    }
162}
163
164
165impl<T: AsFd, LOC> SocketTapCommon for NetworkTap<T, LOC>
166{
167    fn is_conncected(&self) -> bool 
168    {
169        return self.sock.is_some();
170    }
171
172    fn get_fd(&self) -> Option<BorrowedFd>
173    {
174        return self.sock.as_ref().map(|v| v.as_fd());
175    }
176
177    fn get_remote_addr(&self) -> &SocketAddr
178    {
179        return &self.cfg.get_resolver_sa();
180    }
181}
182