1
#![cfg_attr(docsrs, feature(doc_cfg))]
2
#![doc = include_str!("../README.md")]
3
// @@ begin lint list maintained by maint/add_warning @@
4
#![allow(renamed_and_removed_lints)] // @@REMOVE_WHEN(ci_arti_stable)
5
#![allow(unknown_lints)] // @@REMOVE_WHEN(ci_arti_nightly)
6
#![warn(missing_docs)]
7
#![warn(noop_method_call)]
8
#![warn(unreachable_pub)]
9
#![warn(clippy::all)]
10
#![deny(clippy::await_holding_lock)]
11
#![deny(clippy::cargo_common_metadata)]
12
#![deny(clippy::cast_lossless)]
13
#![deny(clippy::checked_conversions)]
14
#![allow(clippy::cognitive_complexity)] // See arti#2556
15
#![deny(clippy::debug_assert_with_mut_call)]
16
#![deny(clippy::exhaustive_enums)]
17
#![deny(clippy::exhaustive_structs)]
18
#![deny(clippy::expl_impl_clone_on_copy)]
19
#![deny(clippy::fallible_impl_from)]
20
#![deny(clippy::implicit_clone)]
21
#![deny(clippy::large_stack_arrays)]
22
#![warn(clippy::manual_ok_or)]
23
#![deny(clippy::missing_docs_in_private_items)]
24
#![warn(clippy::needless_borrow)]
25
#![warn(clippy::needless_pass_by_value)]
26
#![warn(clippy::option_option)]
27
#![deny(clippy::print_stderr)]
28
#![deny(clippy::print_stdout)]
29
#![warn(clippy::rc_buffer)]
30
#![deny(clippy::ref_option_ref)]
31
#![warn(clippy::semicolon_if_nothing_returned)]
32
#![warn(clippy::trait_duplication_in_bounds)]
33
#![deny(clippy::unchecked_time_subtraction)]
34
#![deny(clippy::unnecessary_wraps)]
35
#![warn(clippy::unseparated_literal_suffix)]
36
#![deny(clippy::unwrap_used)]
37
#![deny(clippy::mod_module_files)]
38
#![allow(clippy::let_unit_value)] // This can reasonably be done for explicitness
39
#![allow(clippy::uninlined_format_args)]
40
#![allow(clippy::significant_drop_in_scrutinee)] // arti/-/merge_requests/588/#note_2812945
41
#![allow(clippy::result_large_err)] // temporary workaround for arti#587
42
#![allow(clippy::needless_raw_string_hashes)] // complained-about code is fine, often best
43
#![allow(clippy::needless_lifetimes)] // See arti#1765
44
#![allow(mismatched_lifetime_syntaxes)] // temporary workaround for arti#2060
45
#![allow(clippy::collapsible_if)] // See arti#2342
46
#![deny(clippy::unused_async)]
47
#![deny(clippy::string_slice)] // See arti#2571
48
//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
49

            
50
// TODO #1645 (either remove this, or decide to have it everywhere)
51
#![cfg_attr(
52
    not(all(feature = "full", feature = "experimental")),
53
    allow(unused, unreachable_pub)
54
)]
55

            
56
#[cfg(feature = "bench")]
57
pub mod bench_utils;
58
pub mod channel;
59
pub mod circuit;
60
pub mod client;
61
pub(crate) mod conflux;
62
mod congestion;
63
mod crypto;
64
pub mod memquota;
65
pub mod peer;
66
pub mod stream;
67
pub(crate) mod streammap;
68
pub(crate) mod tunnel;
69
mod util;
70

            
71
#[cfg(feature = "relay")]
72
pub mod relay;
73
#[cfg(feature = "relay")]
74
pub use relay::channel::{RelayChannelAuthMaterial, RelayChannelBuilder};
75

            
76
pub use util::err::{Error, ResolveError};
77
pub use util::skew::ClockSkew;
78

            
79
pub use channel::params::ChannelPaddingInstructions;
80
pub use client::{ClientTunnel, HopLocation, TargetHop, channel::ClientChannelBuilder};
81
pub use congestion::params as ccparams;
82
pub use crypto::cell::{HopNum, HopNumDisplay};
83
pub use stream::flow_ctrl::params::{CellCount, FlowCtrlParameters};
84
#[cfg(feature = "send-control-msg")]
85
pub use {
86
    crate::client::Conversation,
87
    crate::client::msghandler::{MsgHandler, UserMsgHandler},
88
    crate::client::reactor::MetaCellDisposition,
89
};
90

            
91
/// A Result type for this crate.
92
pub type Result<T> = std::result::Result<T, Error>;
93

            
94
use std::fmt::Debug;
95
use tor_memquota::{
96
    HasMemoryCost,
97
    mq_queue::{self, ChannelSpec as _},
98
};
99
use tor_rtcompat::DynTimeProvider;
100

            
101
#[doc(hidden)]
102
pub use {derive_deftly, tor_memquota};
103

            
104
/// Timestamp object that we update whenever we get incoming traffic.
105
///
106
/// Used to implement [`time_since_last_incoming_traffic`]
107
static LAST_INCOMING_TRAFFIC: util::ts::AtomicOptTimestamp = util::ts::AtomicOptTimestamp::new();
108

            
109
/// Called whenever we receive incoming traffic.
110
///
111
/// Used to implement [`time_since_last_incoming_traffic`]
112
#[inline]
113
492
pub(crate) fn note_incoming_traffic() {
114
492
    LAST_INCOMING_TRAFFIC.update();
115
492
}
116

            
117
/// Return the amount of time since we last received "incoming traffic".
118
///
119
/// This is a global counter, and is subject to interference from
120
/// other users of the `tor_proto`.  Its only permissible use is for
121
/// checking how recently we have been definitely able to receive
122
/// incoming traffic.
123
///
124
/// When enabled, this timestamp is updated whenever we receive a valid
125
/// cell, and whenever we complete a channel handshake.
126
///
127
/// Returns `None` if we never received "incoming traffic".
128
649587
pub fn time_since_last_incoming_traffic() -> Option<std::time::Duration> {
129
649587
    LAST_INCOMING_TRAFFIC.time_since_update().map(Into::into)
130
649587
}
131

            
132
/// Make an MPSC queue, of any type, that participates in memquota, but a fake one for testing
133
#[cfg(any(test, feature = "testing"))] // Used by Channel::new_fake which is also feature=testing
134
2484
pub(crate) fn fake_mpsc<T: HasMemoryCost + Debug + Send>(
135
2484
    buffer: usize,
136
2484
) -> (
137
2484
    mq_queue::Sender<T, mq_queue::MpscSpec>,
138
2484
    mq_queue::Receiver<T, mq_queue::MpscSpec>,
139
2484
) {
140
2484
    mq_queue::MpscSpec::new(buffer)
141
2484
        .new_mq(
142
            // The fake Account doesn't care about the data ages, so this will do.
143
            //
144
            // Thiw would be wrong to use generally in tests, where we might want to mock time,
145
            // since we end up, here with totally *different* mocked time.
146
            // But it's OK here, and saves passing a runtime parameter into this function.
147
2484
            DynTimeProvider::new(tor_rtmock::MockRuntime::default()),
148
2484
            &tor_memquota::Account::new_noop(),
149
        )
150
2484
        .expect("create fake mpsc")
151
2484
}
152

            
153
/// Return a list of the protocols [supported](tor_protover::doc_supported)
154
/// by this crate, running as a client.
155
10916
pub fn supported_client_protocols() -> tor_protover::Protocols {
156
    use tor_protover::named::*;
157
    // WARNING: REMOVING ELEMENTS FROM THIS LIST CAN BE DANGEROUS!
158
    // SEE [`tor_protover::doc_changing`]
159
10916
    let mut protocols = vec![
160
        LINK_V4,
161
        LINK_V5,
162
        LINKAUTH_ED25519_SHA256_EXPORTER,
163
        FLOWCTRL_AUTH_SENDME,
164
        RELAY_NTOR,
165
        RELAY_EXTEND_IPv6,
166
        RELAY_NTORV3,
167
        RELAY_NEGOTIATE_SUBPROTO,
168
    ];
169
    #[cfg(feature = "flowctl-cc")]
170
10916
    protocols.push(FLOWCTRL_CC);
171
    #[cfg(feature = "counter-galois-onion")]
172
10916
    protocols.push(RELAY_CRYPT_CGO);
173

            
174
10916
    protocols.into_iter().collect()
175
10916
}
176

            
177
#[cfg(test)]
178
mod test {
179
    // @@ begin test lint list maintained by maint/add_warning @@
180
    #![allow(clippy::bool_assert_comparison)]
181
    #![allow(clippy::clone_on_copy)]
182
    #![allow(clippy::dbg_macro)]
183
    #![allow(clippy::mixed_attributes_style)]
184
    #![allow(clippy::print_stderr)]
185
    #![allow(clippy::print_stdout)]
186
    #![allow(clippy::single_char_pattern)]
187
    #![allow(clippy::unwrap_used)]
188
    #![allow(clippy::unchecked_time_subtraction)]
189
    #![allow(clippy::useless_vec)]
190
    #![allow(clippy::needless_pass_by_value)]
191
    #![allow(clippy::string_slice)] // See arti#2571
192
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
193

            
194
    use cfg_if::cfg_if;
195

            
196
    use super::*;
197

            
198
    #[test]
199
    fn protocols() {
200
        let pr = supported_client_protocols();
201
        cfg_if! {
202
            if #[cfg(all(feature="flowctl-cc", feature="counter-galois-onion"))] {
203
                let expected = "FlowCtrl=1-2 Link=4-5 LinkAuth=3 Relay=2-6".parse().unwrap();
204
            } else if #[cfg(feature="flowctl-cc")] {
205
                let expected = "FlowCtrl=1-2 Link=4-5 LinkAuth=3 Relay=2-5".parse().unwrap();
206
                // (Note that we don't have to check for cgo without cc, since that isn't possible.)
207
            } else {
208
                let expected = "FlowCtrl=1 Link=4-5 LinkAuth=3 Relay=2-5".parse().unwrap();
209
            }
210
        }
211
        assert_eq!(pr, expected);
212
    }
213
}