stem_rs/lib.rs
1//! # stem-rs
2//!
3//! A Rust implementation of the Stem library for Tor control protocol interaction.
4//!
5//! # Overview
6//!
7//! stem-rs provides idiomatic Rust APIs for interacting with Tor's control protocol,
8//! maintaining functional parity with Python Stem. The library enables:
9//!
10//! - Control socket communication (TCP and Unix domain sockets)
11//! - All authentication methods (NONE, PASSWORD, COOKIE, SAFECOOKIE)
12//! - High-level Controller API for Tor interaction
13//! - Complete descriptor parsing (server, micro, consensus, extra-info, hidden service)
14//! - Event subscription and handling
15//! - Exit policy parsing and evaluation
16//! - ORPort relay communication
17//! - Version parsing and comparison
18//!
19//! # Architecture
20//!
21//! The library is organized into these primary modules:
22//!
23//! - [`socket`]: Low-level control socket communication
24//! - [`auth`]: Authentication methods and protocol info
25//! - [`controller`]: High-level Controller API
26//! - [`descriptor`]: Tor descriptor parsing
27//! - [`events`]: Event types and handling
28//! - [`exit_policy`]: Exit policy evaluation
29//! - [`client`]: Direct ORPort relay communication
30//! - [`response`]: Control protocol response parsing
31//! - [`interpreter`]: Interactive Tor control interpreter
32//! - [`version`]: Tor version parsing and comparison
33//! - [`util`]: Validation utilities for fingerprints, nicknames, etc.
34//!
35//! # Quick Start
36//!
37//! ```rust,no_run
38//! use stem_rs::{controller::Controller, Error};
39//!
40//! #[tokio::main]
41//! async fn main() -> Result<(), Error> {
42//! // Connect to Tor's control port
43//! let mut controller = Controller::from_port("127.0.0.1:9051".parse().unwrap()).await?;
44//!
45//! // Authenticate (auto-detects method)
46//! controller.authenticate(None).await?;
47//!
48//! // Query Tor version
49//! let version = controller.get_version().await?;
50//! println!("Connected to Tor {}", version);
51//!
52//! Ok(())
53//! }
54//! ```
55//!
56//! # Thread Safety
57//!
58//! The [`controller::Controller`] type is `Send` but not `Sync`. For concurrent access,
59//! wrap it in `Arc<Mutex<Controller>>` or use separate connections.
60//!
61//! # Security Considerations
62//!
63//! - Authentication tokens are cleared from memory after use
64//! - Constant-time comparison is used for sensitive data (see [`util::secure_compare`])
65//! - Input validation prevents protocol injection attacks
66//!
67//! # Error Handling
68//!
69//! All fallible operations return [`Result<T, Error>`]. The [`Error`] enum provides
70//! specific error variants for different failure modes:
71//!
72//! - [`Error::Socket`] - I/O and connection failures
73//! - [`Error::Authentication`] - Authentication failures (see [`AuthError`])
74//! - [`Error::OperationFailed`] - Tor rejected the operation
75//! - [`Error::Parse`] - Descriptor parsing failures
76//!
77//! See the [`Error`] documentation for recovery guidance.
78
79#![warn(missing_docs)]
80#![warn(rustdoc::broken_intra_doc_links)]
81
82pub mod auth;
83pub mod client;
84pub mod controller;
85pub mod descriptor;
86pub mod events;
87pub mod exit_policy;
88pub mod interpreter;
89pub mod protocol;
90pub mod response;
91pub mod socket;
92pub mod util;
93pub mod version;
94
95// Re-export commonly used types at crate root
96pub use controller::Controller;
97pub use socket::ControlSocket;
98pub use version::Version;
99
100use std::fmt;
101use thiserror::Error;
102
103/// Errors that can occur during stem-rs operations.
104///
105/// This enum represents all possible error conditions in the library.
106/// Each variant provides specific information about the failure.
107///
108/// # Error Categories
109///
110/// - **I/O Errors**: [`Socket`](Error::Socket) - Connection and communication failures
111/// - **Protocol Errors**: [`Protocol`](Error::Protocol) - Malformed control protocol data
112/// - **Auth Errors**: [`Authentication`](Error::Authentication) - Authentication failures
113/// - **Operation Errors**: [`OperationFailed`](Error::OperationFailed) - Tor rejected the request
114/// - **Parse Errors**: [`Parse`](Error::Parse) - Descriptor parsing failures
115///
116/// # Recovery Guide
117///
118/// | Error | Recoverable | Retry Meaningful |
119/// |-------|-------------|------------------|
120/// | [`Socket`](Error::Socket) | Sometimes | Yes, with backoff |
121/// | [`Protocol`](Error::Protocol) | No | No |
122/// | [`Authentication`](Error::Authentication) | Sometimes | Yes, with different credentials |
123/// | [`OperationFailed`](Error::OperationFailed) | Depends on code | Check error code |
124/// | [`Parse`](Error::Parse) | No | No |
125/// | [`Timeout`](Error::Timeout) | Yes | Yes, with longer timeout |
126/// | [`SocketClosed`](Error::SocketClosed) | Yes | Yes, reconnect first |
127/// | [`Download`](Error::Download) | Sometimes | Yes, with backoff |
128/// | [`DownloadTimeout`](Error::DownloadTimeout) | Yes | Yes, with longer timeout |
129///
130/// # Example
131///
132/// ```rust
133/// use stem_rs::Error;
134///
135/// fn handle_error(err: Error) {
136/// match err {
137/// Error::Socket(io_err) => {
138/// eprintln!("Connection failed: {}", io_err);
139/// // Retry with exponential backoff
140/// }
141/// Error::Authentication(auth_err) => {
142/// eprintln!("Auth failed: {}", auth_err);
143/// // Check credentials or try different auth method
144/// }
145/// Error::Parse { location, reason } => {
146/// eprintln!("Parse error at {}: {}", location, reason);
147/// // Log and skip this descriptor
148/// }
149/// Error::OperationFailed { code, message } => {
150/// eprintln!("Tor rejected request: {} - {}", code, message);
151/// // Check if operation can be retried
152/// }
153/// _ => eprintln!("Error: {}", err),
154/// }
155/// }
156/// ```
157#[derive(Debug, Error)]
158pub enum Error {
159 /// I/O error during socket communication.
160 ///
161 /// This error wraps standard I/O errors that occur during socket operations.
162 /// Common causes include connection refused, connection reset, and network
163 /// unreachable errors.
164 ///
165 /// # Recovery
166 ///
167 /// - Check if Tor is running and the control port is accessible
168 /// - Retry with exponential backoff for transient network issues
169 /// - Verify firewall rules allow the connection
170 #[error("socket error: {0}")]
171 Socket(#[from] std::io::Error),
172
173 /// Malformed data received from the control protocol.
174 ///
175 /// This indicates the data received from Tor doesn't conform to the
176 /// expected control protocol format. This typically indicates a bug
177 /// in either Tor or this library.
178 ///
179 /// # Recovery
180 ///
181 /// This error is not recoverable. Report the issue with the malformed data.
182 #[error("protocol error: {0}")]
183 Protocol(String),
184
185 /// Authentication with Tor failed.
186 ///
187 /// See [`AuthError`] for specific authentication failure reasons.
188 ///
189 /// # Recovery
190 ///
191 /// - Check credentials (password, cookie file path)
192 /// - Verify Tor's authentication configuration
193 /// - Try a different authentication method
194 #[error("authentication failed: {0}")]
195 Authentication(#[from] AuthError),
196
197 /// Tor was unable to complete the requested operation.
198 ///
199 /// This error is returned when Tor understands the request but cannot
200 /// fulfill it. The error code and message provide details about why.
201 ///
202 /// # Fields
203 ///
204 /// - `code`: The numeric error code from Tor (e.g., "552")
205 /// - `message`: Human-readable error description from Tor
206 ///
207 /// # Recovery
208 ///
209 /// Check the error code to determine if retry is meaningful:
210 /// - 4xx codes: Client error, fix the request
211 /// - 5xx codes: Server error, may be transient
212 #[error("operation failed: {code} {message}")]
213 OperationFailed {
214 /// The error code returned by Tor.
215 code: String,
216 /// The error message returned by Tor.
217 message: String,
218 },
219
220 /// The request cannot be satisfied with current Tor state.
221 ///
222 /// This error indicates a valid request that Tor cannot fulfill due to
223 /// its current state (e.g., requesting a circuit when Tor is not connected).
224 ///
225 /// # Recovery
226 ///
227 /// Wait for Tor to reach the required state, then retry.
228 #[error("unsatisfiable request: {0}")]
229 UnsatisfiableRequest(String),
230
231 /// The request was malformed or invalid.
232 ///
233 /// This indicates a programming error - the request doesn't conform
234 /// to the control protocol specification.
235 ///
236 /// # Recovery
237 ///
238 /// Fix the request format. This is not a transient error.
239 #[error("invalid request: {0}")]
240 InvalidRequest(String),
241
242 /// The request contained invalid arguments.
243 ///
244 /// Similar to [`InvalidRequest`](Error::InvalidRequest), but specifically
245 /// for argument validation failures.
246 ///
247 /// # Recovery
248 ///
249 /// Fix the arguments. This is not a transient error.
250 #[error("invalid arguments: {0}")]
251 InvalidArguments(String),
252
253 /// Failed to parse a descriptor or other structured data.
254 ///
255 /// This error occurs when parsing Tor descriptors (server descriptors,
256 /// consensus documents, etc.) and the data doesn't match the expected format.
257 ///
258 /// # Fields
259 ///
260 /// - `location`: Where in the data the parse error occurred
261 /// - `reason`: Description of what was expected vs. found
262 ///
263 /// # Recovery
264 ///
265 /// This error is not recoverable for the specific descriptor. Log the
266 /// error and skip to the next descriptor if processing multiple.
267 #[error("parse error at {location}: {reason}")]
268 Parse {
269 /// Location in the data where parsing failed.
270 location: String,
271 /// Description of the parse failure.
272 reason: String,
273 },
274
275 /// Failed to download a resource from the network.
276 ///
277 /// This error occurs when downloading descriptors or other data from
278 /// directory authorities or mirrors.
279 ///
280 /// # Fields
281 ///
282 /// - `url`: The URL that failed to download
283 /// - `reason`: Description of the failure
284 ///
285 /// # Recovery
286 ///
287 /// - Retry with exponential backoff
288 /// - Try a different directory authority or mirror
289 #[error("download failed: {url} - {reason}")]
290 Download {
291 /// The URL that failed to download.
292 url: String,
293 /// The reason for the download failure.
294 reason: String,
295 },
296
297 /// Download timed out before completing.
298 ///
299 /// The configured timeout was reached before the download completed.
300 ///
301 /// # Recovery
302 ///
303 /// - Increase the timeout value
304 /// - Try a different server
305 /// - Check network connectivity
306 #[error("download timeout: {url}")]
307 DownloadTimeout {
308 /// The URL that timed out.
309 url: String,
310 },
311
312 /// A general operation timeout occurred.
313 ///
314 /// The operation did not complete within the expected time.
315 ///
316 /// # Recovery
317 ///
318 /// - Increase timeout if configurable
319 /// - Check if Tor is responsive
320 /// - Retry the operation
321 #[error("timeout")]
322 Timeout,
323
324 /// The control socket was closed unexpectedly.
325 ///
326 /// This indicates the connection to Tor was lost. This can happen if
327 /// Tor exits, the network connection is interrupted, or the socket
328 /// is closed from the other end.
329 ///
330 /// # Recovery
331 ///
332 /// Reconnect to Tor and re-authenticate.
333 #[error("socket closed")]
334 SocketClosed,
335
336 /// The requested descriptor is not available.
337 ///
338 /// Tor doesn't have the requested descriptor cached and cannot
339 /// retrieve it.
340 ///
341 /// # Recovery
342 ///
343 /// - Wait and retry (descriptor may become available)
344 /// - Try downloading from a different source
345 #[error("descriptor unavailable: {0}")]
346 DescriptorUnavailable(String),
347
348 /// Failed to extend or create a circuit.
349 ///
350 /// The circuit could not be built through the requested relays.
351 ///
352 /// # Recovery
353 ///
354 /// - Try different relays
355 /// - Wait for network conditions to improve
356 /// - Check if the target relay is online
357 #[error("circuit extension failed: {0}")]
358 CircuitExtensionFailed(String),
359
360 /// Failed to parse a socket address.
361 ///
362 /// This error occurs when parsing a string into a socket address fails.
363 ///
364 /// # Recovery
365 ///
366 /// Verify the address format is correct (e.g., "127.0.0.1:9051").
367 #[error("address parse error: {0}")]
368 AddrParse(#[from] std::net::AddrParseError),
369}
370
371/// Authentication-specific errors.
372///
373/// These errors provide detailed information about why authentication
374/// with Tor's control port failed.
375///
376/// # Authentication Methods
377///
378/// Tor supports several authentication methods:
379///
380/// - **NONE**: No authentication required (open control port)
381/// - **PASSWORD**: Password-based authentication (HashedControlPassword)
382/// - **COOKIE**: Cookie file authentication (CookieAuthentication)
383/// - **SAFECOOKIE**: Challenge-response cookie authentication (recommended)
384///
385/// # Recovery Guide
386///
387/// | Error | Recovery Action |
388/// |-------|-----------------|
389/// | [`NoMethods`](AuthError::NoMethods) | Configure authentication in torrc |
390/// | [`IncorrectPassword`](AuthError::IncorrectPassword) | Verify password matches HashedControlPassword |
391/// | [`CookieUnreadable`](AuthError::CookieUnreadable) | Check file permissions and path |
392/// | [`IncorrectCookie`](AuthError::IncorrectCookie) | Cookie file may be stale; restart Tor |
393/// | [`ChallengeFailed`](AuthError::ChallengeFailed) | SAFECOOKIE protocol error; try COOKIE |
394/// | [`MissingPassword`](AuthError::MissingPassword) | Provide password for PASSWORD auth |
395///
396/// # Example
397///
398/// ```rust
399/// use stem_rs::AuthError;
400///
401/// fn handle_auth_error(err: AuthError) {
402/// match err {
403/// AuthError::IncorrectPassword => {
404/// eprintln!("Wrong password - check your torrc HashedControlPassword");
405/// }
406/// AuthError::CookieUnreadable(path) => {
407/// eprintln!("Cannot read cookie file: {}", path);
408/// eprintln!("Check file permissions and that Tor is running");
409/// }
410/// AuthError::NoMethods => {
411/// eprintln!("No compatible auth methods - configure torrc");
412/// }
413/// _ => eprintln!("Authentication error: {}", err),
414/// }
415/// }
416/// ```
417#[derive(Debug, Error)]
418pub enum AuthError {
419 /// No compatible authentication methods are available.
420 ///
421 /// Tor's PROTOCOLINFO response didn't include any authentication
422 /// methods that this library supports.
423 ///
424 /// # Recovery
425 ///
426 /// Configure at least one of: CookieAuthentication, HashedControlPassword,
427 /// or disable authentication entirely in torrc.
428 #[error("no authentication methods available")]
429 NoMethods,
430
431 /// The provided password was incorrect.
432 ///
433 /// PASSWORD authentication failed because the password doesn't match
434 /// the HashedControlPassword in torrc.
435 ///
436 /// # Recovery
437 ///
438 /// Verify the password matches what was used to generate HashedControlPassword.
439 /// Use `tor --hash-password` to generate a new hash if needed.
440 #[error("incorrect password")]
441 IncorrectPassword,
442
443 /// The cookie file could not be read.
444 ///
445 /// COOKIE or SAFECOOKIE authentication requires reading a cookie file,
446 /// but the file couldn't be accessed.
447 ///
448 /// # Recovery
449 ///
450 /// - Verify the cookie file path is correct
451 /// - Check file permissions (must be readable by your process)
452 /// - Ensure Tor is running (cookie file is created on startup)
453 #[error("cookie file unreadable: {0}")]
454 CookieUnreadable(String),
455
456 /// The cookie value was incorrect.
457 ///
458 /// The cookie file was read successfully, but Tor rejected the value.
459 /// This can happen if the cookie file is stale (from a previous Tor run).
460 ///
461 /// # Recovery
462 ///
463 /// Restart Tor to generate a fresh cookie file, then retry authentication.
464 #[error("incorrect cookie value")]
465 IncorrectCookie,
466
467 /// The cookie file has an incorrect size.
468 ///
469 /// Tor's cookie file should be exactly 32 bytes. A different size
470 /// indicates file corruption or an incorrect file.
471 ///
472 /// # Recovery
473 ///
474 /// Verify you're reading the correct cookie file. Restart Tor if needed.
475 #[error("incorrect cookie size")]
476 IncorrectCookieSize,
477
478 /// SAFECOOKIE challenge-response failed.
479 ///
480 /// The SAFECOOKIE authentication protocol failed during the
481 /// challenge-response exchange.
482 ///
483 /// # Recovery
484 ///
485 /// - Fall back to COOKIE authentication if available
486 /// - Verify the cookie file is current
487 /// - Check for network issues between client and Tor
488 #[error("safecookie challenge failed")]
489 ChallengeFailed,
490
491 /// SAFECOOKIE authentication is not supported.
492 ///
493 /// The Tor version doesn't support SAFECOOKIE, or it's disabled.
494 ///
495 /// # Recovery
496 ///
497 /// Use COOKIE or PASSWORD authentication instead.
498 #[error("safecookie challenge unsupported")]
499 ChallengeUnsupported,
500
501 /// A security check failed during authentication.
502 ///
503 /// This indicates a potential security issue, such as a mismatch
504 /// in expected vs. received authentication data.
505 ///
506 /// # Recovery
507 ///
508 /// This may indicate a man-in-the-middle attack. Verify your
509 /// connection to Tor is secure.
510 #[error("auth security failure")]
511 SecurityFailure,
512
513 /// PASSWORD authentication was requested but no password provided.
514 ///
515 /// The authenticate method was called without a password, but
516 /// PASSWORD is the only available authentication method.
517 ///
518 /// # Recovery
519 ///
520 /// Provide a password to the authenticate method.
521 #[error("missing password")]
522 MissingPassword,
523
524 /// Tor advertised unrecognized authentication methods.
525 ///
526 /// PROTOCOLINFO returned authentication methods this library
527 /// doesn't recognize. This may indicate a newer Tor version.
528 ///
529 /// # Recovery
530 ///
531 /// Update stem-rs to a newer version that supports these methods.
532 #[error("unrecognized auth methods: {0:?}")]
533 UnrecognizedMethods(Vec<String>),
534
535 /// Wrong socket type for the requested authentication.
536 ///
537 /// Some authentication methods are only valid for certain socket types
538 /// (e.g., Unix domain sockets vs. TCP sockets).
539 ///
540 /// # Recovery
541 ///
542 /// Use a different authentication method appropriate for your socket type.
543 #[error("incorrect socket type")]
544 IncorrectSocketType,
545}
546
547/// Logging severity levels for Tor events.
548///
549/// These levels correspond to Tor's internal logging runlevels and are used
550/// in log events received via the control protocol.
551///
552/// # Severity Order
553///
554/// From most to least severe: [`Err`](Runlevel::Err) > [`Warn`](Runlevel::Warn) >
555/// [`Notice`](Runlevel::Notice) > [`Info`](Runlevel::Info) > [`Debug`](Runlevel::Debug)
556///
557/// # Example
558///
559/// ```rust
560/// use stem_rs::Runlevel;
561///
562/// let level = Runlevel::Notice;
563/// println!("Log level: {}", level); // Prints "NOTICE"
564/// ```
565#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
566pub enum Runlevel {
567 /// Low-level runtime information for debugging.
568 ///
569 /// Very verbose output useful for development and troubleshooting.
570 Debug,
571 /// High-level runtime information.
572 ///
573 /// General operational information about Tor's activities.
574 Info,
575 /// Information that may be helpful to the user.
576 ///
577 /// Normal operational messages that users might want to see.
578 Notice,
579 /// Non-critical issues the user should be aware of.
580 ///
581 /// Problems that don't prevent operation but may need attention.
582 Warn,
583 /// Critical issues that impair Tor's ability to function.
584 ///
585 /// Serious errors that may prevent normal operation.
586 Err,
587}
588
589impl fmt::Display for Runlevel {
590 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
591 match self {
592 Runlevel::Debug => write!(f, "DEBUG"),
593 Runlevel::Info => write!(f, "INFO"),
594 Runlevel::Notice => write!(f, "NOTICE"),
595 Runlevel::Warn => write!(f, "WARN"),
596 Runlevel::Err => write!(f, "ERR"),
597 }
598 }
599}
600
601/// Signals that can be sent to the Tor process.
602///
603/// These signals control Tor's behavior and can be sent via
604/// [`controller::Controller::signal`].
605///
606/// # Signal Pairs
607///
608/// Some signals have Unix signal equivalents:
609/// - [`Reload`](Signal::Reload) / [`Hup`](Signal::Hup) - Reload configuration (SIGHUP)
610/// - [`Shutdown`](Signal::Shutdown) / [`Int`](Signal::Int) - Graceful shutdown (SIGINT)
611/// - [`Dump`](Signal::Dump) / [`Usr1`](Signal::Usr1) - Dump stats (SIGUSR1)
612/// - [`Debug`](Signal::Debug) / [`Usr2`](Signal::Usr2) - Debug logging (SIGUSR2)
613/// - [`Halt`](Signal::Halt) / [`Term`](Signal::Term) - Immediate exit (SIGTERM)
614///
615/// # Example
616///
617/// ```rust,no_run
618/// use stem_rs::{controller::Controller, Signal};
619///
620/// # async fn example() -> Result<(), stem_rs::Error> {
621/// # let mut controller = Controller::from_port("127.0.0.1:9051".parse().unwrap()).await?;
622/// // Request new circuits for privacy
623/// controller.signal(Signal::Newnym).await?;
624///
625/// // Clear DNS cache
626/// controller.signal(Signal::ClearDnsCache).await?;
627/// # Ok(())
628/// # }
629/// ```
630#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
631pub enum Signal {
632 /// Reload configuration files.
633 ///
634 /// Tor will reload torrc and apply changes that can be changed at runtime.
635 /// Equivalent to sending SIGHUP.
636 Reload,
637 /// Alias for [`Reload`](Signal::Reload).
638 ///
639 /// Unix SIGHUP signal equivalent.
640 Hup,
641 /// Controlled shutdown.
642 ///
643 /// Tor will close listeners and exit cleanly after current connections
644 /// complete, waiting ShutdownWaitLength if configured as a relay.
645 Shutdown,
646 /// Alias for [`Shutdown`](Signal::Shutdown).
647 ///
648 /// Unix SIGINT signal equivalent.
649 Int,
650 /// Dump information about open connections and circuits to the log.
651 ///
652 /// Useful for debugging connection issues.
653 Dump,
654 /// Alias for [`Dump`](Signal::Dump).
655 ///
656 /// Unix SIGUSR1 signal equivalent.
657 Usr1,
658 /// Switch logging to DEBUG level.
659 ///
660 /// Temporarily enables debug-level logging until the next RELOAD.
661 Debug,
662 /// Alias for [`Debug`](Signal::Debug).
663 ///
664 /// Unix SIGUSR2 signal equivalent.
665 Usr2,
666 /// Immediate shutdown.
667 ///
668 /// Tor exits immediately without waiting for connections to close.
669 Halt,
670 /// Alias for [`Halt`](Signal::Halt).
671 ///
672 /// Unix SIGTERM signal equivalent.
673 Term,
674 /// Request new circuits for future connections.
675 ///
676 /// Clears the current circuit cache and builds new circuits.
677 /// Also clears the DNS cache. Rate-limited to prevent abuse.
678 /// Use this for privacy when you want to appear as a "new" user.
679 Newnym,
680 /// Clear cached DNS results.
681 ///
682 /// Forces Tor to re-resolve all hostnames on subsequent requests.
683 ClearDnsCache,
684 /// Trigger a heartbeat log message.
685 ///
686 /// Useful for monitoring that Tor is responsive.
687 Heartbeat,
688 /// Wake from dormant mode.
689 ///
690 /// Resumes normal operation if Tor was in dormant mode.
691 /// Disables dormant mode.
692 Active,
693 /// Enter dormant mode.
694 ///
695 /// Reduces resource usage (CPU and network) when Tor is not actively needed.
696 /// Tor will avoid building circuits and making network connections.
697 Dormant,
698}
699
700impl fmt::Display for Signal {
701 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
702 match self {
703 Signal::Reload => write!(f, "RELOAD"),
704 Signal::Hup => write!(f, "HUP"),
705 Signal::Shutdown => write!(f, "SHUTDOWN"),
706 Signal::Int => write!(f, "INT"),
707 Signal::Dump => write!(f, "DUMP"),
708 Signal::Usr1 => write!(f, "USR1"),
709 Signal::Debug => write!(f, "DEBUG"),
710 Signal::Usr2 => write!(f, "USR2"),
711 Signal::Halt => write!(f, "HALT"),
712 Signal::Term => write!(f, "TERM"),
713 Signal::Newnym => write!(f, "NEWNYM"),
714 Signal::ClearDnsCache => write!(f, "CLEARDNSCACHE"),
715 Signal::Heartbeat => write!(f, "HEARTBEAT"),
716 Signal::Active => write!(f, "ACTIVE"),
717 Signal::Dormant => write!(f, "DORMANT"),
718 }
719 }
720}
721
722/// Flags assigned to Tor relays by directory authorities.
723///
724/// These flags indicate various characteristics of relays and are used
725/// for path selection and relay classification.
726///
727/// # Flag Meanings
728///
729/// Flags are assigned based on relay behavior and capabilities:
730/// - Performance flags: [`Fast`](Flag::Fast), [`Stable`](Flag::Stable)
731/// - Role flags: [`Guard`](Flag::Guard), [`Exit`](Flag::Exit), [`Authority`](Flag::Authority)
732/// - Status flags: [`Running`](Flag::Running), [`Valid`](Flag::Valid)
733/// - Warning flags: [`BadExit`](Flag::BadExit), [`BadDirectory`](Flag::BadDirectory)
734///
735/// # Example
736///
737/// ```rust
738/// use stem_rs::Flag;
739///
740/// let flag = Flag::Guard;
741/// println!("Relay flag: {}", flag); // Prints "Guard"
742/// ```
743#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
744pub enum Flag {
745 /// Relay is a directory authority.
746 ///
747 /// This relay is one of the trusted directory authorities that
748 /// vote on the network consensus.
749 Authority,
750 /// Relay shouldn't be used as an exit due to being problematic or malicious.
751 ///
752 /// The relay has been flagged for bad behavior when used as an exit node.
753 BadExit,
754 /// Relay shouldn't be used for directory information.
755 ///
756 /// Note: This flag was removed from Tor but may appear in older descriptors.
757 BadDirectory,
758 /// Relay's exit policy makes it useful as an exit node.
759 ///
760 /// The relay allows exiting to a reasonable number of ports.
761 Exit,
762 /// Relay is suitable for high-bandwidth circuits.
763 ///
764 /// The relay has sufficient bandwidth for performance-sensitive traffic.
765 Fast,
766 /// Relay is suitable for being an entry guard (first hop).
767 ///
768 /// The relay is stable and fast enough to be used as a guard node.
769 Guard,
770 /// Relay is being used as a hidden service directory.
771 ///
772 /// The relay stores and serves hidden service descriptors.
773 HsDir,
774 /// Relay can be referred to by its nickname.
775 ///
776 /// The nickname is unique and verified.
777 Named,
778 /// Relay's Ed25519 key doesn't match the consensus.
779 ///
780 /// There's a mismatch in the relay's Ed25519 identity.
781 NoEdConsensus,
782 /// Relay is currently usable.
783 ///
784 /// The relay is online and responding to connections.
785 Running,
786 /// Relay is suitable for long-lived circuits.
787 ///
788 /// The relay has good uptime and is reliable for persistent connections.
789 Stable,
790 /// Relay descriptor is outdated and should be re-uploaded.
791 ///
792 /// The relay's descriptor is stale and needs to be refreshed.
793 StaleDesc,
794 /// Relay isn't currently bound to a nickname.
795 ///
796 /// The nickname is not verified or is shared with other relays.
797 Unnamed,
798 /// Relay supports the v2 directory protocol.
799 ///
800 /// The relay can serve directory information via the v2 protocol.
801 V2Dir,
802 /// Relay supports the v3 directory protocol.
803 ///
804 /// The relay can serve directory information via the v3 protocol.
805 V3Dir,
806 /// Relay has been validated.
807 ///
808 /// The relay's identity has been verified by the directory authorities.
809 Valid,
810}
811
812impl fmt::Display for Flag {
813 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
814 match self {
815 Flag::Authority => write!(f, "Authority"),
816 Flag::BadExit => write!(f, "BadExit"),
817 Flag::BadDirectory => write!(f, "BadDirectory"),
818 Flag::Exit => write!(f, "Exit"),
819 Flag::Fast => write!(f, "Fast"),
820 Flag::Guard => write!(f, "Guard"),
821 Flag::HsDir => write!(f, "HSDir"),
822 Flag::Named => write!(f, "Named"),
823 Flag::NoEdConsensus => write!(f, "NoEdConsensus"),
824 Flag::Running => write!(f, "Running"),
825 Flag::Stable => write!(f, "Stable"),
826 Flag::StaleDesc => write!(f, "StaleDesc"),
827 Flag::Unnamed => write!(f, "Unnamed"),
828 Flag::V2Dir => write!(f, "V2Dir"),
829 Flag::V3Dir => write!(f, "V3Dir"),
830 Flag::Valid => write!(f, "Valid"),
831 }
832 }
833}
834
835/// Status of a circuit in the Tor network.
836///
837/// Circuits progress through these states during their lifecycle.
838/// Tor may provide statuses not in this enum.
839///
840/// # Circuit Lifecycle
841///
842/// ```text
843/// LAUNCHED -> EXTENDED -> BUILT -> CLOSED
844/// | |
845/// v v
846/// FAILED FAILED
847/// ```
848///
849/// # Example
850///
851/// ```rust
852/// use stem_rs::CircStatus;
853///
854/// let status = CircStatus::Built;
855/// println!("Circuit status: {}", status); // Prints "BUILT"
856/// ```
857#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
858pub enum CircStatus {
859 /// New circuit was created.
860 ///
861 /// The circuit has been initiated but not yet extended to any relays.
862 Launched,
863 /// Circuit finished being created and can accept traffic.
864 ///
865 /// The circuit is fully built and ready for use.
866 Built,
867 /// Waiting to see if there's a circuit with a better guard.
868 ///
869 /// Tor is evaluating whether to use this circuit or wait for a better one.
870 GuardWait,
871 /// Circuit has been extended by a hop.
872 ///
873 /// The circuit is being built and has added another relay.
874 Extended,
875 /// Circuit construction failed.
876 ///
877 /// The circuit could not be completed. See [`CircClosureReason`] for details.
878 Failed,
879 /// Circuit has been closed.
880 ///
881 /// The circuit is no longer usable. See [`CircClosureReason`] for details.
882 Closed,
883}
884
885impl fmt::Display for CircStatus {
886 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
887 match self {
888 CircStatus::Launched => write!(f, "LAUNCHED"),
889 CircStatus::Built => write!(f, "BUILT"),
890 CircStatus::GuardWait => write!(f, "GUARD_WAIT"),
891 CircStatus::Extended => write!(f, "EXTENDED"),
892 CircStatus::Failed => write!(f, "FAILED"),
893 CircStatus::Closed => write!(f, "CLOSED"),
894 }
895 }
896}
897
898/// Attributes about how a circuit is built.
899///
900/// These flags describe special properties of circuit construction.
901/// Introduced in Tor version 0.2.3.11.
902///
903/// # Example
904///
905/// ```rust
906/// use stem_rs::CircBuildFlag;
907///
908/// let flag = CircBuildFlag::IsInternal;
909/// println!("Build flag: {}", flag); // Prints "IS_INTERNAL"
910/// ```
911#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
912pub enum CircBuildFlag {
913 /// Single hop circuit to fetch directory information.
914 ///
915 /// A one-hop tunnel used for directory fetches, not for user traffic.
916 OneHopTunnel,
917 /// Circuit that won't be used for client traffic.
918 ///
919 /// Internal circuits are used for Tor's own operations.
920 IsInternal,
921 /// Circuit only includes high capacity relays.
922 ///
923 /// Built for bandwidth-intensive operations.
924 NeedCapacity,
925 /// Circuit only includes relays with high uptime.
926 ///
927 /// Built for long-lived connections that need stability.
928 NeedUptime,
929}
930
931impl fmt::Display for CircBuildFlag {
932 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
933 match self {
934 CircBuildFlag::OneHopTunnel => write!(f, "ONEHOP_TUNNEL"),
935 CircBuildFlag::IsInternal => write!(f, "IS_INTERNAL"),
936 CircBuildFlag::NeedCapacity => write!(f, "NEED_CAPACITY"),
937 CircBuildFlag::NeedUptime => write!(f, "NEED_UPTIME"),
938 }
939 }
940}
941
942/// Purpose of a circuit.
943///
944/// Describes what a circuit is intended for. Introduced in Tor version 0.2.1.6.
945///
946/// # Example
947///
948/// ```rust
949/// use stem_rs::CircPurpose;
950///
951/// let purpose = CircPurpose::General;
952/// println!("Circuit purpose: {}", purpose); // Prints "GENERAL"
953/// ```
954#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
955pub enum CircPurpose {
956 /// General client traffic or fetching directory information.
957 ///
958 /// Standard circuits used for normal Tor operations.
959 General,
960 /// Client-side introduction point for a hidden service circuit.
961 ///
962 /// Used when connecting to a hidden service's introduction point.
963 HsClientIntro,
964 /// Client-side hidden service rendezvous circuit.
965 ///
966 /// Used for the rendezvous connection when accessing a hidden service.
967 HsClientRend,
968 /// Server-side introduction point for a hidden service circuit.
969 ///
970 /// Used by hidden services to establish introduction points.
971 HsServiceIntro,
972 /// Server-side hidden service rendezvous circuit.
973 ///
974 /// Used by hidden services for rendezvous connections.
975 HsServiceRend,
976 /// Testing to see if we're reachable as a relay.
977 ///
978 /// Self-test circuits to verify relay reachability.
979 Testing,
980 /// Circuit that was built by a controller.
981 ///
982 /// Explicitly created via the control protocol.
983 Controller,
984 /// Circuit being kept around to measure timeout.
985 ///
986 /// Used for circuit build time measurement.
987 MeasureTimeout,
988 /// Constructed in advance for hidden service vanguards.
989 ///
990 /// Pre-built circuits for vanguard protection.
991 HsVanguards,
992 /// Probing if circuits are being maliciously closed.
993 ///
994 /// Used to detect path bias attacks.
995 PathBiasTesting,
996 /// Circuit is unused but remains open to disguise closure time.
997 ///
998 /// Padding circuits to prevent traffic analysis.
999 CircuitPadding,
1000}
1001
1002impl fmt::Display for CircPurpose {
1003 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1004 match self {
1005 CircPurpose::General => write!(f, "GENERAL"),
1006 CircPurpose::HsClientIntro => write!(f, "HS_CLIENT_INTRO"),
1007 CircPurpose::HsClientRend => write!(f, "HS_CLIENT_REND"),
1008 CircPurpose::HsServiceIntro => write!(f, "HS_SERVICE_INTRO"),
1009 CircPurpose::HsServiceRend => write!(f, "HS_SERVICE_REND"),
1010 CircPurpose::Testing => write!(f, "TESTING"),
1011 CircPurpose::Controller => write!(f, "CONTROLLER"),
1012 CircPurpose::MeasureTimeout => write!(f, "MEASURE_TIMEOUT"),
1013 CircPurpose::HsVanguards => write!(f, "HS_VANGUARDS"),
1014 CircPurpose::PathBiasTesting => write!(f, "PATH_BIAS_TESTING"),
1015 CircPurpose::CircuitPadding => write!(f, "CIRCUIT_PADDING"),
1016 }
1017 }
1018}
1019
1020/// Reason that a circuit is being closed or failed to be established.
1021///
1022/// Provides detailed information about why a circuit ended.
1023///
1024/// # Example
1025///
1026/// ```rust
1027/// use stem_rs::CircClosureReason;
1028///
1029/// let reason = CircClosureReason::Timeout;
1030/// println!("Closure reason: {}", reason); // Prints "TIMEOUT"
1031/// ```
1032#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1033pub enum CircClosureReason {
1034 /// No reason given.
1035 None,
1036 /// Violation in the Tor protocol.
1037 ///
1038 /// A relay sent malformed or unexpected data.
1039 TorProtocol,
1040 /// Internal error.
1041 ///
1042 /// An internal error occurred in Tor.
1043 Internal,
1044 /// Requested by the client via a TRUNCATE command.
1045 ///
1046 /// The circuit was explicitly closed by the client.
1047 Requested,
1048 /// Relay is currently hibernating.
1049 ///
1050 /// The relay is in low-power mode and not accepting circuits.
1051 Hibernating,
1052 /// Relay is out of memory, sockets, or circuit IDs.
1053 ///
1054 /// The relay has exhausted resources.
1055 ResourceLimit,
1056 /// Unable to contact the relay.
1057 ///
1058 /// Network connectivity issue to the next hop.
1059 ConnectFailed,
1060 /// Relay had the wrong OR identification.
1061 ///
1062 /// The relay's identity key didn't match what was expected.
1063 OrIdentity,
1064 /// Connection failed after being established.
1065 ///
1066 /// The OR connection was closed unexpectedly.
1067 OrConnClosed,
1068 /// Circuit has expired.
1069 ///
1070 /// The circuit exceeded MaxCircuitDirtiness lifetime.
1071 Finished,
1072 /// Circuit construction timed out.
1073 ///
1074 /// The circuit took too long to build.
1075 Timeout,
1076 /// Circuit unexpectedly closed.
1077 ///
1078 /// The circuit was destroyed by a relay.
1079 Destroyed,
1080 /// Not enough relays to make a circuit.
1081 ///
1082 /// Insufficient relays available for path selection.
1083 NoPath,
1084 /// Requested hidden service does not exist.
1085 ///
1086 /// The onion address is invalid or the service is offline.
1087 NoSuchService,
1088 /// Same as Timeout but left open for measurement.
1089 ///
1090 /// Circuit timed out but was kept for build time measurement.
1091 MeasurementExpired,
1092 /// Introduction point is redundant with another circuit.
1093 ///
1094 /// Another circuit already serves this introduction point.
1095 IpNowRedundant,
1096}
1097
1098impl fmt::Display for CircClosureReason {
1099 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1100 match self {
1101 CircClosureReason::None => write!(f, "NONE"),
1102 CircClosureReason::TorProtocol => write!(f, "TORPROTOCOL"),
1103 CircClosureReason::Internal => write!(f, "INTERNAL"),
1104 CircClosureReason::Requested => write!(f, "REQUESTED"),
1105 CircClosureReason::Hibernating => write!(f, "HIBERNATING"),
1106 CircClosureReason::ResourceLimit => write!(f, "RESOURCELIMIT"),
1107 CircClosureReason::ConnectFailed => write!(f, "CONNECTFAILED"),
1108 CircClosureReason::OrIdentity => write!(f, "OR_IDENTITY"),
1109 CircClosureReason::OrConnClosed => write!(f, "OR_CONN_CLOSED"),
1110 CircClosureReason::Finished => write!(f, "FINISHED"),
1111 CircClosureReason::Timeout => write!(f, "TIMEOUT"),
1112 CircClosureReason::Destroyed => write!(f, "DESTROYED"),
1113 CircClosureReason::NoPath => write!(f, "NOPATH"),
1114 CircClosureReason::NoSuchService => write!(f, "NOSUCHSERVICE"),
1115 CircClosureReason::MeasurementExpired => write!(f, "MEASUREMENT_EXPIRED"),
1116 CircClosureReason::IpNowRedundant => write!(f, "IP_NOW_REDUNDANT"),
1117 }
1118 }
1119}
1120
1121/// Type of change reflected in a circuit by a CIRC_MINOR event.
1122///
1123/// These events indicate minor changes to circuits that don't affect
1124/// their overall status.
1125///
1126/// # Example
1127///
1128/// ```rust
1129/// use stem_rs::CircEvent;
1130///
1131/// let event = CircEvent::PurposeChanged;
1132/// println!("Circuit event: {}", event); // Prints "PURPOSE_CHANGED"
1133/// ```
1134#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1135pub enum CircEvent {
1136 /// Circuit purpose or hidden service state has changed.
1137 ///
1138 /// The circuit's intended use has been modified.
1139 PurposeChanged,
1140 /// Circuit connections are being reused for a different circuit.
1141 ///
1142 /// An existing circuit is being repurposed.
1143 Cannibalized,
1144}
1145
1146impl fmt::Display for CircEvent {
1147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1148 match self {
1149 CircEvent::PurposeChanged => write!(f, "PURPOSE_CHANGED"),
1150 CircEvent::Cannibalized => write!(f, "CANNIBALIZED"),
1151 }
1152 }
1153}
1154
1155/// State of a hidden service circuit.
1156///
1157/// These states track the progress of hidden service connections.
1158/// Introduced in Tor version 0.2.3.11.
1159///
1160/// # State Prefixes
1161///
1162/// - `HSCI_*` - Client-side introduction point
1163/// - `HSCR_*` - Client-side rendezvous point
1164/// - `HSSI_*` - Service-side introduction point
1165/// - `HSSR_*` - Service-side rendezvous point
1166///
1167/// # Example
1168///
1169/// ```rust
1170/// use stem_rs::HiddenServiceState;
1171///
1172/// let state = HiddenServiceState::HscrJoined;
1173/// println!("HS state: {}", state); // Prints "HSCR_JOINED"
1174/// ```
1175#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1176pub enum HiddenServiceState {
1177 /// Client connecting to the introduction point.
1178 HsciConnecting,
1179 /// Client sent INTRODUCE1 and awaiting reply.
1180 HsciIntroSent,
1181 /// Client received reply, circuit is closing.
1182 HsciDone,
1183 /// Client connecting to rendezvous point.
1184 HscrConnecting,
1185 /// Rendezvous point established, awaiting introduction.
1186 HscrEstablishedIdle,
1187 /// Introduction received, awaiting rendezvous.
1188 HscrEstablishedWaiting,
1189 /// Client connected to the hidden service.
1190 HscrJoined,
1191 /// Service connecting to introduction point.
1192 HssiConnecting,
1193 /// Service established introduction point.
1194 HssiEstablished,
1195 /// Service connecting to rendezvous point.
1196 HssrConnecting,
1197 /// Service connected to rendezvous point.
1198 HssrJoined,
1199}
1200
1201impl fmt::Display for HiddenServiceState {
1202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1203 match self {
1204 HiddenServiceState::HsciConnecting => write!(f, "HSCI_CONNECTING"),
1205 HiddenServiceState::HsciIntroSent => write!(f, "HSCI_INTRO_SENT"),
1206 HiddenServiceState::HsciDone => write!(f, "HSCI_DONE"),
1207 HiddenServiceState::HscrConnecting => write!(f, "HSCR_CONNECTING"),
1208 HiddenServiceState::HscrEstablishedIdle => write!(f, "HSCR_ESTABLISHED_IDLE"),
1209 HiddenServiceState::HscrEstablishedWaiting => write!(f, "HSCR_ESTABLISHED_WAITING"),
1210 HiddenServiceState::HscrJoined => write!(f, "HSCR_JOINED"),
1211 HiddenServiceState::HssiConnecting => write!(f, "HSSI_CONNECTING"),
1212 HiddenServiceState::HssiEstablished => write!(f, "HSSI_ESTABLISHED"),
1213 HiddenServiceState::HssrConnecting => write!(f, "HSSR_CONNECTING"),
1214 HiddenServiceState::HssrJoined => write!(f, "HSSR_JOINED"),
1215 }
1216 }
1217}
1218
1219/// Status of a stream going through Tor.
1220///
1221/// Streams represent individual TCP connections tunneled through circuits.
1222///
1223/// # Example
1224///
1225/// ```rust
1226/// use stem_rs::StreamStatus;
1227///
1228/// let status = StreamStatus::Succeeded;
1229/// println!("Stream status: {}", status); // Prints "SUCCEEDED"
1230/// ```
1231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1232pub enum StreamStatus {
1233 /// Request for a new connection.
1234 New,
1235 /// Request to resolve an address.
1236 NewResolve,
1237 /// Address is being re-mapped to another.
1238 Remap,
1239 /// Sent a connect cell along a circuit.
1240 SentConnect,
1241 /// Sent a resolve cell along a circuit.
1242 SentResolve,
1243 /// Stream has been established.
1244 Succeeded,
1245 /// Stream is detached and won't be re-established.
1246 Failed,
1247 /// Stream is detached but might be re-established.
1248 Detached,
1249 /// Awaiting a controller's ATTACHSTREAM request.
1250 ControllerWait,
1251 /// Stream has closed.
1252 Closed,
1253}
1254
1255impl fmt::Display for StreamStatus {
1256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1257 match self {
1258 StreamStatus::New => write!(f, "NEW"),
1259 StreamStatus::NewResolve => write!(f, "NEWRESOLVE"),
1260 StreamStatus::Remap => write!(f, "REMAP"),
1261 StreamStatus::SentConnect => write!(f, "SENTCONNECT"),
1262 StreamStatus::SentResolve => write!(f, "SENTRESOLVE"),
1263 StreamStatus::Succeeded => write!(f, "SUCCEEDED"),
1264 StreamStatus::Failed => write!(f, "FAILED"),
1265 StreamStatus::Detached => write!(f, "DETACHED"),
1266 StreamStatus::ControllerWait => write!(f, "CONTROLLER_WAIT"),
1267 StreamStatus::Closed => write!(f, "CLOSED"),
1268 }
1269 }
1270}
1271
1272/// Reason that a stream is being closed or failed to be established.
1273///
1274/// Provides detailed information about why a stream ended.
1275///
1276/// # Example
1277///
1278/// ```rust
1279/// use stem_rs::StreamClosureReason;
1280///
1281/// let reason = StreamClosureReason::Done;
1282/// println!("Closure reason: {}", reason); // Prints "DONE"
1283/// ```
1284#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1285pub enum StreamClosureReason {
1286 /// None of the other reasons apply.
1287 Misc,
1288 /// Unable to resolve the hostname.
1289 ResolveFailed,
1290 /// Remote host refused the connection.
1291 ConnectRefused,
1292 /// OR refuses to connect due to exit policy.
1293 ExitPolicy,
1294 /// Circuit is being shut down.
1295 Destroy,
1296 /// Connection has been closed normally.
1297 Done,
1298 /// Connection timed out.
1299 Timeout,
1300 /// Routing error while contacting the destination.
1301 NoRoute,
1302 /// Relay is temporarily hibernating.
1303 Hibernating,
1304 /// Internal error at the relay.
1305 Internal,
1306 /// Relay has insufficient resources.
1307 ResourceLimit,
1308 /// Connection was unexpectedly reset.
1309 ConnReset,
1310 /// Violation in the Tor protocol.
1311 TorProtocol,
1312 /// Directory info requested from non-directory relay.
1313 NotDirectory,
1314 /// Endpoint has sent a RELAY_END cell.
1315 End,
1316 /// Endpoint was a private address (127.0.0.1, 10.0.0.1, etc).
1317 PrivateAddr,
1318}
1319
1320impl fmt::Display for StreamClosureReason {
1321 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1322 match self {
1323 StreamClosureReason::Misc => write!(f, "MISC"),
1324 StreamClosureReason::ResolveFailed => write!(f, "RESOLVEFAILED"),
1325 StreamClosureReason::ConnectRefused => write!(f, "CONNECTREFUSED"),
1326 StreamClosureReason::ExitPolicy => write!(f, "EXITPOLICY"),
1327 StreamClosureReason::Destroy => write!(f, "DESTROY"),
1328 StreamClosureReason::Done => write!(f, "DONE"),
1329 StreamClosureReason::Timeout => write!(f, "TIMEOUT"),
1330 StreamClosureReason::NoRoute => write!(f, "NOROUTE"),
1331 StreamClosureReason::Hibernating => write!(f, "HIBERNATING"),
1332 StreamClosureReason::Internal => write!(f, "INTERNAL"),
1333 StreamClosureReason::ResourceLimit => write!(f, "RESOURCELIMIT"),
1334 StreamClosureReason::ConnReset => write!(f, "CONNRESET"),
1335 StreamClosureReason::TorProtocol => write!(f, "TORPROTOCOL"),
1336 StreamClosureReason::NotDirectory => write!(f, "NOTDIRECTORY"),
1337 StreamClosureReason::End => write!(f, "END"),
1338 StreamClosureReason::PrivateAddr => write!(f, "PRIVATE_ADDR"),
1339 }
1340 }
1341}
1342
1343/// Cause of a stream being remapped to another address.
1344///
1345/// # Example
1346///
1347/// ```rust
1348/// use stem_rs::StreamSource;
1349///
1350/// let source = StreamSource::Cache;
1351/// println!("Stream source: {}", source); // Prints "CACHE"
1352/// ```
1353#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1354pub enum StreamSource {
1355 /// Tor is remapping because of a cached answer.
1356 Cache,
1357 /// Exit relay requested the remap.
1358 Exit,
1359}
1360
1361impl fmt::Display for StreamSource {
1362 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1363 match self {
1364 StreamSource::Cache => write!(f, "CACHE"),
1365 StreamSource::Exit => write!(f, "EXIT"),
1366 }
1367 }
1368}
1369
1370/// Purpose of a stream.
1371///
1372/// Describes what the stream is being used for. Only provided with new streams.
1373///
1374/// # Example
1375///
1376/// ```rust
1377/// use stem_rs::StreamPurpose;
1378///
1379/// let purpose = StreamPurpose::User;
1380/// println!("Stream purpose: {}", purpose); // Prints "USER"
1381/// ```
1382#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1383pub enum StreamPurpose {
1384 /// Fetching directory information (descriptors, consensus, etc).
1385 DirFetch,
1386 /// Uploading our descriptor to an authority.
1387 DirUpload,
1388 /// User initiated DNS request.
1389 DnsRequest,
1390 /// Checking that our directory port is reachable externally.
1391 DirportTest,
1392 /// Either relaying user traffic or not one of the above categories.
1393 User,
1394}
1395
1396impl fmt::Display for StreamPurpose {
1397 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1398 match self {
1399 StreamPurpose::DirFetch => write!(f, "DIR_FETCH"),
1400 StreamPurpose::DirUpload => write!(f, "DIR_UPLOAD"),
1401 StreamPurpose::DnsRequest => write!(f, "DNS_REQUEST"),
1402 StreamPurpose::DirportTest => write!(f, "DIRPORT_TEST"),
1403 StreamPurpose::User => write!(f, "USER"),
1404 }
1405 }
1406}
1407
1408/// Status of an OR (Onion Router) connection.
1409///
1410/// OR connections are the TLS connections between Tor relays.
1411///
1412/// # Example
1413///
1414/// ```rust
1415/// use stem_rs::OrStatus;
1416///
1417/// let status = OrStatus::Connected;
1418/// println!("OR status: {}", status); // Prints "CONNECTED"
1419/// ```
1420#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1421pub enum OrStatus {
1422 /// Received OR connection, starting server-side handshake.
1423 New,
1424 /// Launched outbound OR connection, starting client-side handshake.
1425 Launched,
1426 /// OR connection has been established.
1427 Connected,
1428 /// Attempt to establish OR connection failed.
1429 Failed,
1430 /// OR connection has been closed.
1431 Closed,
1432}
1433
1434impl fmt::Display for OrStatus {
1435 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1436 match self {
1437 OrStatus::New => write!(f, "NEW"),
1438 OrStatus::Launched => write!(f, "LAUNCHED"),
1439 OrStatus::Connected => write!(f, "CONNECTED"),
1440 OrStatus::Failed => write!(f, "FAILED"),
1441 OrStatus::Closed => write!(f, "CLOSED"),
1442 }
1443 }
1444}
1445
1446/// Reason that an OR connection is being closed or failed.
1447///
1448/// # Example
1449///
1450/// ```rust
1451/// use stem_rs::OrClosureReason;
1452///
1453/// let reason = OrClosureReason::Done;
1454/// println!("OR closure reason: {}", reason); // Prints "DONE"
1455/// ```
1456#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1457pub enum OrClosureReason {
1458 /// OR connection shut down cleanly.
1459 Done,
1460 /// Got ECONNREFUSED when connecting to the relay.
1461 ConnectRefused,
1462 /// Identity of the relay wasn't what we expected.
1463 Identity,
1464 /// Got ECONNRESET or similar error from relay.
1465 ConnectReset,
1466 /// Got ETIMEOUT or similar error from relay.
1467 Timeout,
1468 /// Got ENOTCONN, ENETUNREACH, ENETDOWN, EHOSTUNREACH, or similar.
1469 NoRoute,
1470 /// Got a different kind of I/O error from relay.
1471 IoError,
1472 /// Relay has insufficient resources.
1473 ResourceLimit,
1474 /// Connection refused for another reason.
1475 Misc,
1476 /// No pluggable transport was available.
1477 PtMissing,
1478}
1479
1480impl fmt::Display for OrClosureReason {
1481 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1482 match self {
1483 OrClosureReason::Done => write!(f, "DONE"),
1484 OrClosureReason::ConnectRefused => write!(f, "CONNECTREFUSED"),
1485 OrClosureReason::Identity => write!(f, "IDENTITY"),
1486 OrClosureReason::ConnectReset => write!(f, "CONNECTRESET"),
1487 OrClosureReason::Timeout => write!(f, "TIMEOUT"),
1488 OrClosureReason::NoRoute => write!(f, "NOROUTE"),
1489 OrClosureReason::IoError => write!(f, "IOERROR"),
1490 OrClosureReason::ResourceLimit => write!(f, "RESOURCELIMIT"),
1491 OrClosureReason::Misc => write!(f, "MISC"),
1492 OrClosureReason::PtMissing => write!(f, "PT_MISSING"),
1493 }
1494 }
1495}
1496
1497/// Type of guard relay usage.
1498///
1499/// # Example
1500///
1501/// ```rust
1502/// use stem_rs::GuardType;
1503///
1504/// let guard_type = GuardType::Entry;
1505/// println!("Guard type: {}", guard_type); // Prints "ENTRY"
1506/// ```
1507#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1508pub enum GuardType {
1509 /// Used to connect to the Tor network (entry guard).
1510 Entry,
1511}
1512
1513impl fmt::Display for GuardType {
1514 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1515 match self {
1516 GuardType::Entry => write!(f, "ENTRY"),
1517 }
1518 }
1519}
1520
1521/// Status of a guard relay.
1522///
1523/// # Example
1524///
1525/// ```rust
1526/// use stem_rs::GuardStatus;
1527///
1528/// let status = GuardStatus::Up;
1529/// println!("Guard status: {}", status); // Prints "UP"
1530/// ```
1531#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1532pub enum GuardStatus {
1533 /// New guard that we weren't previously using.
1534 New,
1535 /// Removed from use as one of our guards.
1536 Dropped,
1537 /// Guard is now reachable.
1538 Up,
1539 /// Guard is now unreachable.
1540 Down,
1541 /// Consensus or relay considers this relay unusable as a guard.
1542 Bad,
1543 /// Consensus or relay considers this relay usable as a guard.
1544 Good,
1545}
1546
1547impl fmt::Display for GuardStatus {
1548 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1549 match self {
1550 GuardStatus::New => write!(f, "NEW"),
1551 GuardStatus::Dropped => write!(f, "DROPPED"),
1552 GuardStatus::Up => write!(f, "UP"),
1553 GuardStatus::Down => write!(f, "DOWN"),
1554 GuardStatus::Bad => write!(f, "BAD"),
1555 GuardStatus::Good => write!(f, "GOOD"),
1556 }
1557 }
1558}
1559
1560/// Way in which the timeout value of a circuit is changing.
1561///
1562/// # Example
1563///
1564/// ```rust
1565/// use stem_rs::TimeoutSetType;
1566///
1567/// let timeout_type = TimeoutSetType::Computed;
1568/// println!("Timeout type: {}", timeout_type); // Prints "COMPUTED"
1569/// ```
1570#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1571pub enum TimeoutSetType {
1572 /// Tor has computed a new timeout based on prior circuits.
1573 Computed,
1574 /// Timeout reverted to its default.
1575 Reset,
1576 /// Timeout reverted to default until network connectivity recovers.
1577 Suspended,
1578 /// Throwing out timeout value from when the network was down.
1579 Discard,
1580 /// Resumed calculations to determine the proper timeout.
1581 Resume,
1582}
1583
1584impl fmt::Display for TimeoutSetType {
1585 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1586 match self {
1587 TimeoutSetType::Computed => write!(f, "COMPUTED"),
1588 TimeoutSetType::Reset => write!(f, "RESET"),
1589 TimeoutSetType::Suspended => write!(f, "SUSPENDED"),
1590 TimeoutSetType::Discard => write!(f, "DISCARD"),
1591 TimeoutSetType::Resume => write!(f, "RESUME"),
1592 }
1593 }
1594}
1595
1596/// Action being taken in a HS_DESC event.
1597///
1598/// # Example
1599///
1600/// ```rust
1601/// use stem_rs::HsDescAction;
1602///
1603/// let action = HsDescAction::Received;
1604/// println!("HS_DESC action: {}", action); // Prints "RECEIVED"
1605/// ```
1606#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1607pub enum HsDescAction {
1608 /// Uncached hidden service descriptor is being requested.
1609 Requested,
1610 /// Descriptor is being uploaded with HSPOST.
1611 Upload,
1612 /// Hidden service descriptor has been retrieved.
1613 Received,
1614 /// Descriptor was uploaded with HSPOST.
1615 Uploaded,
1616 /// Fetched descriptor was ignored (already have v0 descriptor).
1617 Ignore,
1618 /// We were unable to retrieve the descriptor.
1619 Failed,
1620 /// Hidden service descriptor was just created.
1621 Created,
1622}
1623
1624impl fmt::Display for HsDescAction {
1625 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1626 match self {
1627 HsDescAction::Requested => write!(f, "REQUESTED"),
1628 HsDescAction::Upload => write!(f, "UPLOAD"),
1629 HsDescAction::Received => write!(f, "RECEIVED"),
1630 HsDescAction::Uploaded => write!(f, "UPLOADED"),
1631 HsDescAction::Ignore => write!(f, "IGNORE"),
1632 HsDescAction::Failed => write!(f, "FAILED"),
1633 HsDescAction::Created => write!(f, "CREATED"),
1634 }
1635 }
1636}
1637
1638/// Reason for a hidden service descriptor fetch to fail.
1639///
1640/// # Example
1641///
1642/// ```rust
1643/// use stem_rs::HsDescReason;
1644///
1645/// let reason = HsDescReason::NotFound;
1646/// println!("HS_DESC reason: {}", reason); // Prints "NOT_FOUND"
1647/// ```
1648#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1649pub enum HsDescReason {
1650 /// Descriptor was unparseable.
1651 BadDesc,
1652 /// Hidden service directory refused to provide the descriptor.
1653 QueryRejected,
1654 /// Descriptor was rejected by the hidden service directory.
1655 UploadRejected,
1656 /// Descriptor with the given identifier wasn't found.
1657 NotFound,
1658 /// No hidden service directory was found.
1659 QueryNoHsDir,
1660 /// Request was throttled (rate limited).
1661 QueryRateLimited,
1662 /// Failure type is unknown.
1663 Unexpected,
1664}
1665
1666impl fmt::Display for HsDescReason {
1667 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1668 match self {
1669 HsDescReason::BadDesc => write!(f, "BAD_DESC"),
1670 HsDescReason::QueryRejected => write!(f, "QUERY_REJECTED"),
1671 HsDescReason::UploadRejected => write!(f, "UPLOAD_REJECTED"),
1672 HsDescReason::NotFound => write!(f, "NOT_FOUND"),
1673 HsDescReason::QueryNoHsDir => write!(f, "QUERY_NO_HSDIR"),
1674 HsDescReason::QueryRateLimited => write!(f, "QUERY_RATE_LIMITED"),
1675 HsDescReason::Unexpected => write!(f, "UNEXPECTED"),
1676 }
1677 }
1678}
1679
1680/// Type of authentication for a HS_DESC event.
1681///
1682/// # Example
1683///
1684/// ```rust
1685/// use stem_rs::HsAuth;
1686///
1687/// let auth = HsAuth::NoAuth;
1688/// println!("HS auth: {}", auth); // Prints "NO_AUTH"
1689/// ```
1690#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1691pub enum HsAuth {
1692 /// No authentication required.
1693 NoAuth,
1694 /// General hidden service authentication.
1695 BasicAuth,
1696 /// Authentication that hides service activity from unauthorized clients.
1697 StealthAuth,
1698 /// Unrecognized method of authentication.
1699 Unknown,
1700}
1701
1702impl fmt::Display for HsAuth {
1703 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1704 match self {
1705 HsAuth::NoAuth => write!(f, "NO_AUTH"),
1706 HsAuth::BasicAuth => write!(f, "BASIC_AUTH"),
1707 HsAuth::StealthAuth => write!(f, "STEALTH_AUTH"),
1708 HsAuth::Unknown => write!(f, "UNKNOWN"),
1709 }
1710 }
1711}
1712
1713/// Types of events that can be subscribed to via the control protocol.
1714///
1715/// Use with [`controller::Controller::set_events`] to subscribe to events.
1716///
1717/// # Example
1718///
1719/// ```rust
1720/// use stem_rs::EventType;
1721///
1722/// let event = EventType::Circ;
1723/// println!("Event type: {}", event); // Prints "CIRC"
1724/// ```
1725#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1726pub enum EventType {
1727 /// Circuit status changed.
1728 Circ,
1729 /// Stream status changed.
1730 Stream,
1731 /// OR connection status changed.
1732 OrConn,
1733 /// Bandwidth used in the last second.
1734 Bw,
1735 /// Debug-level log message.
1736 Debug,
1737 /// Info-level log message.
1738 Info,
1739 /// Notice-level log message.
1740 Notice,
1741 /// Warning-level log message.
1742 Warn,
1743 /// Error-level log message.
1744 Err,
1745 /// New descriptors available.
1746 NewDesc,
1747 /// Address mapping changed.
1748 AddrMap,
1749 /// New descriptors uploaded to us as an authority.
1750 AuthDir,
1751 /// Our descriptor changed.
1752 DescChanged,
1753 /// General status event.
1754 Status,
1755 /// Guard status changed.
1756 Guard,
1757 /// Network status changed.
1758 Ns,
1759 /// Per-stream bandwidth.
1760 StreamBw,
1761 /// Periodic client summary (bridge/relay only).
1762 ClientsSeen,
1763 /// New consensus available.
1764 NewConsensus,
1765 /// Circuit build timeout changed.
1766 BuildTimeoutSet,
1767 /// Signal received.
1768 Signal,
1769 /// Configuration changed.
1770 ConfChanged,
1771 /// Minor circuit event.
1772 CircMinor,
1773 /// Pluggable transport launched.
1774 TransportLaunched,
1775 /// Per-connection bandwidth.
1776 ConnBw,
1777 /// Per-circuit bandwidth.
1778 CircBw,
1779 /// Cell statistics.
1780 CellStats,
1781 /// Hidden service descriptor event.
1782 HsDesc,
1783 /// Hidden service descriptor content.
1784 HsDescContent,
1785 /// Network liveness changed.
1786 NetworkLiveness,
1787 /// Pluggable transport log message.
1788 PtLog,
1789 /// Pluggable transport status.
1790 PtStatus,
1791}
1792
1793impl fmt::Display for EventType {
1794 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1795 match self {
1796 EventType::Circ => write!(f, "CIRC"),
1797 EventType::Stream => write!(f, "STREAM"),
1798 EventType::OrConn => write!(f, "ORCONN"),
1799 EventType::Bw => write!(f, "BW"),
1800 EventType::Debug => write!(f, "DEBUG"),
1801 EventType::Info => write!(f, "INFO"),
1802 EventType::Notice => write!(f, "NOTICE"),
1803 EventType::Warn => write!(f, "WARN"),
1804 EventType::Err => write!(f, "ERR"),
1805 EventType::NewDesc => write!(f, "NEWDESC"),
1806 EventType::AddrMap => write!(f, "ADDRMAP"),
1807 EventType::AuthDir => write!(f, "AUTHDIR_NEWDESCS"),
1808 EventType::DescChanged => write!(f, "DESCCHANGED"),
1809 EventType::Status => write!(f, "STATUS_GENERAL"),
1810 EventType::Guard => write!(f, "GUARD"),
1811 EventType::Ns => write!(f, "NS"),
1812 EventType::StreamBw => write!(f, "STREAM_BW"),
1813 EventType::ClientsSeen => write!(f, "CLIENTS_SEEN"),
1814 EventType::NewConsensus => write!(f, "NEWCONSENSUS"),
1815 EventType::BuildTimeoutSet => write!(f, "BUILDTIMEOUT_SET"),
1816 EventType::Signal => write!(f, "SIGNAL"),
1817 EventType::ConfChanged => write!(f, "CONF_CHANGED"),
1818 EventType::CircMinor => write!(f, "CIRC_MINOR"),
1819 EventType::TransportLaunched => write!(f, "TRANSPORT_LAUNCHED"),
1820 EventType::ConnBw => write!(f, "CONN_BW"),
1821 EventType::CircBw => write!(f, "CIRC_BW"),
1822 EventType::CellStats => write!(f, "CELL_STATS"),
1823 EventType::HsDesc => write!(f, "HS_DESC"),
1824 EventType::HsDescContent => write!(f, "HS_DESC_CONTENT"),
1825 EventType::NetworkLiveness => write!(f, "NETWORK_LIVENESS"),
1826 EventType::PtLog => write!(f, "PT_LOG"),
1827 EventType::PtStatus => write!(f, "PT_STATUS"),
1828 }
1829 }
1830}
1831
1832/// Source of a status event.
1833///
1834/// # Example
1835///
1836/// ```rust
1837/// use stem_rs::StatusType;
1838///
1839/// let status = StatusType::General;
1840/// println!("Status type: {}", status); // Prints "GENERAL"
1841/// ```
1842#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1843pub enum StatusType {
1844 /// General Tor activity, not specifically as a client or relay.
1845 General,
1846 /// Related to our activity as a Tor client.
1847 Client,
1848 /// Related to our activity as a Tor relay.
1849 Server,
1850}
1851
1852impl fmt::Display for StatusType {
1853 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1854 match self {
1855 StatusType::General => write!(f, "GENERAL"),
1856 StatusType::Client => write!(f, "CLIENT"),
1857 StatusType::Server => write!(f, "SERVER"),
1858 }
1859 }
1860}
1861
1862/// Purpose for a Tor connection.
1863///
1864/// # Example
1865///
1866/// ```rust
1867/// use stem_rs::ConnectionType;
1868///
1869/// let conn_type = ConnectionType::Or;
1870/// println!("Connection type: {}", conn_type); // Prints "OR"
1871/// ```
1872#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1873pub enum ConnectionType {
1874 /// Carrying traffic within the Tor network.
1875 Or,
1876 /// Fetching or sending Tor descriptor data.
1877 Dir,
1878 /// Carrying traffic between Tor network and external destination.
1879 Exit,
1880}
1881
1882impl fmt::Display for ConnectionType {
1883 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1884 match self {
1885 ConnectionType::Or => write!(f, "OR"),
1886 ConnectionType::Dir => write!(f, "DIR"),
1887 ConnectionType::Exit => write!(f, "EXIT"),
1888 }
1889 }
1890}
1891
1892/// Bucket categories for TB_EMPTY events.
1893///
1894/// Token buckets are used for rate limiting in Tor.
1895///
1896/// # Example
1897///
1898/// ```rust
1899/// use stem_rs::TokenBucket;
1900///
1901/// let bucket = TokenBucket::Global;
1902/// println!("Token bucket: {}", bucket); // Prints "GLOBAL"
1903/// ```
1904#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1905pub enum TokenBucket {
1906 /// Global token bucket for overall bandwidth.
1907 Global,
1908 /// Relay token bucket for relay traffic.
1909 Relay,
1910 /// Bucket used for OR connections.
1911 OrConn,
1912}
1913
1914impl fmt::Display for TokenBucket {
1915 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1916 match self {
1917 TokenBucket::Global => write!(f, "GLOBAL"),
1918 TokenBucket::Relay => write!(f, "RELAY"),
1919 TokenBucket::OrConn => write!(f, "ORCONN"),
1920 }
1921 }
1922}
1923
1924/// Actions that directory authorities take with relay descriptors.
1925///
1926/// # Example
1927///
1928/// ```rust
1929/// use stem_rs::AuthDescriptorAction;
1930///
1931/// let action = AuthDescriptorAction::Accepted;
1932/// println!("Auth action: {}", action); // Prints "ACCEPTED"
1933/// ```
1934#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1935pub enum AuthDescriptorAction {
1936 /// Accepting the descriptor as the newest version.
1937 Accepted,
1938 /// Descriptor rejected without notifying the relay.
1939 Dropped,
1940 /// Relay notified that its descriptor has been rejected.
1941 Rejected,
1942}
1943
1944impl fmt::Display for AuthDescriptorAction {
1945 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1946 match self {
1947 AuthDescriptorAction::Accepted => write!(f, "ACCEPTED"),
1948 AuthDescriptorAction::Dropped => write!(f, "DROPPED"),
1949 AuthDescriptorAction::Rejected => write!(f, "REJECTED"),
1950 }
1951 }
1952}
1953
1954/// Bridge distribution methods.
1955///
1956/// Specifies how a bridge relay should be distributed to users.
1957///
1958/// # Example
1959///
1960/// ```rust
1961/// use stem_rs::BridgeDistribution;
1962///
1963/// let dist = BridgeDistribution::Https;
1964/// println!("Distribution: {}", dist); // Prints "https"
1965/// ```
1966#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1967pub enum BridgeDistribution {
1968 /// Distribute via any method.
1969 Any,
1970 /// Distribute via HTTPS (bridges.torproject.org).
1971 Https,
1972 /// Distribute via email.
1973 Email,
1974 /// Distribute via Moat (built into Tor Browser).
1975 Moat,
1976 /// Distribute via Hyphae.
1977 Hyphae,
1978}
1979
1980impl fmt::Display for BridgeDistribution {
1981 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1982 match self {
1983 BridgeDistribution::Any => write!(f, "any"),
1984 BridgeDistribution::Https => write!(f, "https"),
1985 BridgeDistribution::Email => write!(f, "email"),
1986 BridgeDistribution::Moat => write!(f, "moat"),
1987 BridgeDistribution::Hyphae => write!(f, "hyphae"),
1988 }
1989 }
1990}
1991
1992#[cfg(test)]
1993mod tests {
1994 use super::*;
1995
1996 #[test]
1997 fn test_runlevel_display() {
1998 assert_eq!(format!("{}", Runlevel::Debug), "DEBUG");
1999 assert_eq!(format!("{}", Runlevel::Info), "INFO");
2000 assert_eq!(format!("{}", Runlevel::Notice), "NOTICE");
2001 assert_eq!(format!("{}", Runlevel::Warn), "WARN");
2002 assert_eq!(format!("{}", Runlevel::Err), "ERR");
2003 }
2004
2005 #[test]
2006 fn test_signal_display() {
2007 assert_eq!(format!("{}", Signal::Reload), "RELOAD");
2008 assert_eq!(format!("{}", Signal::Hup), "HUP");
2009 assert_eq!(format!("{}", Signal::Shutdown), "SHUTDOWN");
2010 assert_eq!(format!("{}", Signal::Int), "INT");
2011 assert_eq!(format!("{}", Signal::Dump), "DUMP");
2012 assert_eq!(format!("{}", Signal::Usr1), "USR1");
2013 assert_eq!(format!("{}", Signal::Debug), "DEBUG");
2014 assert_eq!(format!("{}", Signal::Usr2), "USR2");
2015 assert_eq!(format!("{}", Signal::Halt), "HALT");
2016 assert_eq!(format!("{}", Signal::Term), "TERM");
2017 assert_eq!(format!("{}", Signal::Newnym), "NEWNYM");
2018 assert_eq!(format!("{}", Signal::ClearDnsCache), "CLEARDNSCACHE");
2019 assert_eq!(format!("{}", Signal::Heartbeat), "HEARTBEAT");
2020 assert_eq!(format!("{}", Signal::Active), "ACTIVE");
2021 assert_eq!(format!("{}", Signal::Dormant), "DORMANT");
2022 }
2023
2024 #[test]
2025 fn test_flag_display() {
2026 assert_eq!(format!("{}", Flag::Authority), "Authority");
2027 assert_eq!(format!("{}", Flag::BadExit), "BadExit");
2028 assert_eq!(format!("{}", Flag::BadDirectory), "BadDirectory");
2029 assert_eq!(format!("{}", Flag::Exit), "Exit");
2030 assert_eq!(format!("{}", Flag::Fast), "Fast");
2031 assert_eq!(format!("{}", Flag::Guard), "Guard");
2032 assert_eq!(format!("{}", Flag::HsDir), "HSDir");
2033 assert_eq!(format!("{}", Flag::Named), "Named");
2034 assert_eq!(format!("{}", Flag::NoEdConsensus), "NoEdConsensus");
2035 assert_eq!(format!("{}", Flag::Running), "Running");
2036 assert_eq!(format!("{}", Flag::Stable), "Stable");
2037 assert_eq!(format!("{}", Flag::StaleDesc), "StaleDesc");
2038 assert_eq!(format!("{}", Flag::Unnamed), "Unnamed");
2039 assert_eq!(format!("{}", Flag::V2Dir), "V2Dir");
2040 assert_eq!(format!("{}", Flag::V3Dir), "V3Dir");
2041 assert_eq!(format!("{}", Flag::Valid), "Valid");
2042 }
2043
2044 #[test]
2045 fn test_circ_status_display() {
2046 assert_eq!(format!("{}", CircStatus::Launched), "LAUNCHED");
2047 assert_eq!(format!("{}", CircStatus::Built), "BUILT");
2048 assert_eq!(format!("{}", CircStatus::GuardWait), "GUARD_WAIT");
2049 assert_eq!(format!("{}", CircStatus::Extended), "EXTENDED");
2050 assert_eq!(format!("{}", CircStatus::Failed), "FAILED");
2051 assert_eq!(format!("{}", CircStatus::Closed), "CLOSED");
2052 }
2053
2054 #[test]
2055 fn test_circ_build_flag_display() {
2056 assert_eq!(format!("{}", CircBuildFlag::OneHopTunnel), "ONEHOP_TUNNEL");
2057 assert_eq!(format!("{}", CircBuildFlag::IsInternal), "IS_INTERNAL");
2058 assert_eq!(format!("{}", CircBuildFlag::NeedCapacity), "NEED_CAPACITY");
2059 assert_eq!(format!("{}", CircBuildFlag::NeedUptime), "NEED_UPTIME");
2060 }
2061
2062 #[test]
2063 fn test_circ_purpose_display() {
2064 assert_eq!(format!("{}", CircPurpose::General), "GENERAL");
2065 assert_eq!(format!("{}", CircPurpose::HsClientIntro), "HS_CLIENT_INTRO");
2066 assert_eq!(format!("{}", CircPurpose::HsClientRend), "HS_CLIENT_REND");
2067 assert_eq!(
2068 format!("{}", CircPurpose::HsServiceIntro),
2069 "HS_SERVICE_INTRO"
2070 );
2071 assert_eq!(format!("{}", CircPurpose::HsServiceRend), "HS_SERVICE_REND");
2072 assert_eq!(format!("{}", CircPurpose::Testing), "TESTING");
2073 assert_eq!(format!("{}", CircPurpose::Controller), "CONTROLLER");
2074 assert_eq!(
2075 format!("{}", CircPurpose::MeasureTimeout),
2076 "MEASURE_TIMEOUT"
2077 );
2078 assert_eq!(format!("{}", CircPurpose::HsVanguards), "HS_VANGUARDS");
2079 assert_eq!(
2080 format!("{}", CircPurpose::PathBiasTesting),
2081 "PATH_BIAS_TESTING"
2082 );
2083 assert_eq!(
2084 format!("{}", CircPurpose::CircuitPadding),
2085 "CIRCUIT_PADDING"
2086 );
2087 }
2088
2089 #[test]
2090 fn test_circ_closure_reason_display() {
2091 assert_eq!(format!("{}", CircClosureReason::None), "NONE");
2092 assert_eq!(format!("{}", CircClosureReason::TorProtocol), "TORPROTOCOL");
2093 assert_eq!(format!("{}", CircClosureReason::Internal), "INTERNAL");
2094 assert_eq!(format!("{}", CircClosureReason::Requested), "REQUESTED");
2095 assert_eq!(format!("{}", CircClosureReason::Hibernating), "HIBERNATING");
2096 assert_eq!(
2097 format!("{}", CircClosureReason::ResourceLimit),
2098 "RESOURCELIMIT"
2099 );
2100 assert_eq!(
2101 format!("{}", CircClosureReason::ConnectFailed),
2102 "CONNECTFAILED"
2103 );
2104 assert_eq!(format!("{}", CircClosureReason::OrIdentity), "OR_IDENTITY");
2105 assert_eq!(
2106 format!("{}", CircClosureReason::OrConnClosed),
2107 "OR_CONN_CLOSED"
2108 );
2109 assert_eq!(format!("{}", CircClosureReason::Finished), "FINISHED");
2110 assert_eq!(format!("{}", CircClosureReason::Timeout), "TIMEOUT");
2111 assert_eq!(format!("{}", CircClosureReason::Destroyed), "DESTROYED");
2112 assert_eq!(format!("{}", CircClosureReason::NoPath), "NOPATH");
2113 assert_eq!(
2114 format!("{}", CircClosureReason::NoSuchService),
2115 "NOSUCHSERVICE"
2116 );
2117 assert_eq!(
2118 format!("{}", CircClosureReason::MeasurementExpired),
2119 "MEASUREMENT_EXPIRED"
2120 );
2121 assert_eq!(
2122 format!("{}", CircClosureReason::IpNowRedundant),
2123 "IP_NOW_REDUNDANT"
2124 );
2125 }
2126
2127 #[test]
2128 fn test_circ_event_display() {
2129 assert_eq!(format!("{}", CircEvent::PurposeChanged), "PURPOSE_CHANGED");
2130 assert_eq!(format!("{}", CircEvent::Cannibalized), "CANNIBALIZED");
2131 }
2132
2133 #[test]
2134 fn test_hidden_service_state_display() {
2135 assert_eq!(
2136 format!("{}", HiddenServiceState::HsciConnecting),
2137 "HSCI_CONNECTING"
2138 );
2139 assert_eq!(
2140 format!("{}", HiddenServiceState::HsciIntroSent),
2141 "HSCI_INTRO_SENT"
2142 );
2143 assert_eq!(format!("{}", HiddenServiceState::HsciDone), "HSCI_DONE");
2144 assert_eq!(
2145 format!("{}", HiddenServiceState::HscrConnecting),
2146 "HSCR_CONNECTING"
2147 );
2148 assert_eq!(
2149 format!("{}", HiddenServiceState::HscrEstablishedIdle),
2150 "HSCR_ESTABLISHED_IDLE"
2151 );
2152 assert_eq!(
2153 format!("{}", HiddenServiceState::HscrEstablishedWaiting),
2154 "HSCR_ESTABLISHED_WAITING"
2155 );
2156 assert_eq!(format!("{}", HiddenServiceState::HscrJoined), "HSCR_JOINED");
2157 assert_eq!(
2158 format!("{}", HiddenServiceState::HssiConnecting),
2159 "HSSI_CONNECTING"
2160 );
2161 assert_eq!(
2162 format!("{}", HiddenServiceState::HssiEstablished),
2163 "HSSI_ESTABLISHED"
2164 );
2165 assert_eq!(
2166 format!("{}", HiddenServiceState::HssrConnecting),
2167 "HSSR_CONNECTING"
2168 );
2169 assert_eq!(format!("{}", HiddenServiceState::HssrJoined), "HSSR_JOINED");
2170 }
2171
2172 #[test]
2173 fn test_stream_status_display() {
2174 assert_eq!(format!("{}", StreamStatus::New), "NEW");
2175 assert_eq!(format!("{}", StreamStatus::NewResolve), "NEWRESOLVE");
2176 assert_eq!(format!("{}", StreamStatus::Remap), "REMAP");
2177 assert_eq!(format!("{}", StreamStatus::SentConnect), "SENTCONNECT");
2178 assert_eq!(format!("{}", StreamStatus::SentResolve), "SENTRESOLVE");
2179 assert_eq!(format!("{}", StreamStatus::Succeeded), "SUCCEEDED");
2180 assert_eq!(format!("{}", StreamStatus::Failed), "FAILED");
2181 assert_eq!(format!("{}", StreamStatus::Detached), "DETACHED");
2182 assert_eq!(
2183 format!("{}", StreamStatus::ControllerWait),
2184 "CONTROLLER_WAIT"
2185 );
2186 assert_eq!(format!("{}", StreamStatus::Closed), "CLOSED");
2187 }
2188
2189 #[test]
2190 fn test_stream_closure_reason_display() {
2191 assert_eq!(format!("{}", StreamClosureReason::Misc), "MISC");
2192 assert_eq!(
2193 format!("{}", StreamClosureReason::ResolveFailed),
2194 "RESOLVEFAILED"
2195 );
2196 assert_eq!(
2197 format!("{}", StreamClosureReason::ConnectRefused),
2198 "CONNECTREFUSED"
2199 );
2200 assert_eq!(format!("{}", StreamClosureReason::ExitPolicy), "EXITPOLICY");
2201 assert_eq!(format!("{}", StreamClosureReason::Destroy), "DESTROY");
2202 assert_eq!(format!("{}", StreamClosureReason::Done), "DONE");
2203 assert_eq!(format!("{}", StreamClosureReason::Timeout), "TIMEOUT");
2204 assert_eq!(format!("{}", StreamClosureReason::NoRoute), "NOROUTE");
2205 assert_eq!(
2206 format!("{}", StreamClosureReason::Hibernating),
2207 "HIBERNATING"
2208 );
2209 assert_eq!(format!("{}", StreamClosureReason::Internal), "INTERNAL");
2210 assert_eq!(
2211 format!("{}", StreamClosureReason::ResourceLimit),
2212 "RESOURCELIMIT"
2213 );
2214 assert_eq!(format!("{}", StreamClosureReason::ConnReset), "CONNRESET");
2215 assert_eq!(
2216 format!("{}", StreamClosureReason::TorProtocol),
2217 "TORPROTOCOL"
2218 );
2219 assert_eq!(
2220 format!("{}", StreamClosureReason::NotDirectory),
2221 "NOTDIRECTORY"
2222 );
2223 assert_eq!(format!("{}", StreamClosureReason::End), "END");
2224 assert_eq!(
2225 format!("{}", StreamClosureReason::PrivateAddr),
2226 "PRIVATE_ADDR"
2227 );
2228 }
2229
2230 #[test]
2231 fn test_stream_source_display() {
2232 assert_eq!(format!("{}", StreamSource::Cache), "CACHE");
2233 assert_eq!(format!("{}", StreamSource::Exit), "EXIT");
2234 }
2235
2236 #[test]
2237 fn test_stream_purpose_display() {
2238 assert_eq!(format!("{}", StreamPurpose::DirFetch), "DIR_FETCH");
2239 assert_eq!(format!("{}", StreamPurpose::DirUpload), "DIR_UPLOAD");
2240 assert_eq!(format!("{}", StreamPurpose::DnsRequest), "DNS_REQUEST");
2241 assert_eq!(format!("{}", StreamPurpose::DirportTest), "DIRPORT_TEST");
2242 assert_eq!(format!("{}", StreamPurpose::User), "USER");
2243 }
2244
2245 #[test]
2246 fn test_or_status_display() {
2247 assert_eq!(format!("{}", OrStatus::New), "NEW");
2248 assert_eq!(format!("{}", OrStatus::Launched), "LAUNCHED");
2249 assert_eq!(format!("{}", OrStatus::Connected), "CONNECTED");
2250 assert_eq!(format!("{}", OrStatus::Failed), "FAILED");
2251 assert_eq!(format!("{}", OrStatus::Closed), "CLOSED");
2252 }
2253
2254 #[test]
2255 fn test_or_closure_reason_display() {
2256 assert_eq!(format!("{}", OrClosureReason::Done), "DONE");
2257 assert_eq!(
2258 format!("{}", OrClosureReason::ConnectRefused),
2259 "CONNECTREFUSED"
2260 );
2261 assert_eq!(format!("{}", OrClosureReason::Identity), "IDENTITY");
2262 assert_eq!(format!("{}", OrClosureReason::ConnectReset), "CONNECTRESET");
2263 assert_eq!(format!("{}", OrClosureReason::Timeout), "TIMEOUT");
2264 assert_eq!(format!("{}", OrClosureReason::NoRoute), "NOROUTE");
2265 assert_eq!(format!("{}", OrClosureReason::IoError), "IOERROR");
2266 assert_eq!(
2267 format!("{}", OrClosureReason::ResourceLimit),
2268 "RESOURCELIMIT"
2269 );
2270 assert_eq!(format!("{}", OrClosureReason::Misc), "MISC");
2271 assert_eq!(format!("{}", OrClosureReason::PtMissing), "PT_MISSING");
2272 }
2273
2274 #[test]
2275 fn test_guard_type_display() {
2276 assert_eq!(format!("{}", GuardType::Entry), "ENTRY");
2277 }
2278
2279 #[test]
2280 fn test_guard_status_display() {
2281 assert_eq!(format!("{}", GuardStatus::New), "NEW");
2282 assert_eq!(format!("{}", GuardStatus::Dropped), "DROPPED");
2283 assert_eq!(format!("{}", GuardStatus::Up), "UP");
2284 assert_eq!(format!("{}", GuardStatus::Down), "DOWN");
2285 assert_eq!(format!("{}", GuardStatus::Bad), "BAD");
2286 assert_eq!(format!("{}", GuardStatus::Good), "GOOD");
2287 }
2288
2289 #[test]
2290 fn test_timeout_set_type_display() {
2291 assert_eq!(format!("{}", TimeoutSetType::Computed), "COMPUTED");
2292 assert_eq!(format!("{}", TimeoutSetType::Reset), "RESET");
2293 assert_eq!(format!("{}", TimeoutSetType::Suspended), "SUSPENDED");
2294 assert_eq!(format!("{}", TimeoutSetType::Discard), "DISCARD");
2295 assert_eq!(format!("{}", TimeoutSetType::Resume), "RESUME");
2296 }
2297
2298 #[test]
2299 fn test_hs_desc_action_display() {
2300 assert_eq!(format!("{}", HsDescAction::Requested), "REQUESTED");
2301 assert_eq!(format!("{}", HsDescAction::Upload), "UPLOAD");
2302 assert_eq!(format!("{}", HsDescAction::Received), "RECEIVED");
2303 assert_eq!(format!("{}", HsDescAction::Uploaded), "UPLOADED");
2304 assert_eq!(format!("{}", HsDescAction::Ignore), "IGNORE");
2305 assert_eq!(format!("{}", HsDescAction::Failed), "FAILED");
2306 assert_eq!(format!("{}", HsDescAction::Created), "CREATED");
2307 }
2308
2309 #[test]
2310 fn test_hs_desc_reason_display() {
2311 assert_eq!(format!("{}", HsDescReason::BadDesc), "BAD_DESC");
2312 assert_eq!(format!("{}", HsDescReason::QueryRejected), "QUERY_REJECTED");
2313 assert_eq!(
2314 format!("{}", HsDescReason::UploadRejected),
2315 "UPLOAD_REJECTED"
2316 );
2317 assert_eq!(format!("{}", HsDescReason::NotFound), "NOT_FOUND");
2318 assert_eq!(format!("{}", HsDescReason::QueryNoHsDir), "QUERY_NO_HSDIR");
2319 assert_eq!(
2320 format!("{}", HsDescReason::QueryRateLimited),
2321 "QUERY_RATE_LIMITED"
2322 );
2323 assert_eq!(format!("{}", HsDescReason::Unexpected), "UNEXPECTED");
2324 }
2325
2326 #[test]
2327 fn test_hs_auth_display() {
2328 assert_eq!(format!("{}", HsAuth::NoAuth), "NO_AUTH");
2329 assert_eq!(format!("{}", HsAuth::BasicAuth), "BASIC_AUTH");
2330 assert_eq!(format!("{}", HsAuth::StealthAuth), "STEALTH_AUTH");
2331 assert_eq!(format!("{}", HsAuth::Unknown), "UNKNOWN");
2332 }
2333
2334 #[test]
2335 fn test_event_type_display() {
2336 assert_eq!(format!("{}", EventType::Circ), "CIRC");
2337 assert_eq!(format!("{}", EventType::Stream), "STREAM");
2338 assert_eq!(format!("{}", EventType::OrConn), "ORCONN");
2339 assert_eq!(format!("{}", EventType::Bw), "BW");
2340 assert_eq!(format!("{}", EventType::Debug), "DEBUG");
2341 assert_eq!(format!("{}", EventType::Info), "INFO");
2342 assert_eq!(format!("{}", EventType::Notice), "NOTICE");
2343 assert_eq!(format!("{}", EventType::Warn), "WARN");
2344 assert_eq!(format!("{}", EventType::Err), "ERR");
2345 assert_eq!(format!("{}", EventType::NewDesc), "NEWDESC");
2346 assert_eq!(format!("{}", EventType::AddrMap), "ADDRMAP");
2347 assert_eq!(format!("{}", EventType::AuthDir), "AUTHDIR_NEWDESCS");
2348 assert_eq!(format!("{}", EventType::DescChanged), "DESCCHANGED");
2349 assert_eq!(format!("{}", EventType::Status), "STATUS_GENERAL");
2350 assert_eq!(format!("{}", EventType::Guard), "GUARD");
2351 assert_eq!(format!("{}", EventType::Ns), "NS");
2352 assert_eq!(format!("{}", EventType::StreamBw), "STREAM_BW");
2353 assert_eq!(format!("{}", EventType::ClientsSeen), "CLIENTS_SEEN");
2354 assert_eq!(format!("{}", EventType::NewConsensus), "NEWCONSENSUS");
2355 assert_eq!(
2356 format!("{}", EventType::BuildTimeoutSet),
2357 "BUILDTIMEOUT_SET"
2358 );
2359 assert_eq!(format!("{}", EventType::Signal), "SIGNAL");
2360 assert_eq!(format!("{}", EventType::ConfChanged), "CONF_CHANGED");
2361 assert_eq!(format!("{}", EventType::CircMinor), "CIRC_MINOR");
2362 assert_eq!(
2363 format!("{}", EventType::TransportLaunched),
2364 "TRANSPORT_LAUNCHED"
2365 );
2366 assert_eq!(format!("{}", EventType::ConnBw), "CONN_BW");
2367 assert_eq!(format!("{}", EventType::CircBw), "CIRC_BW");
2368 assert_eq!(format!("{}", EventType::CellStats), "CELL_STATS");
2369 assert_eq!(format!("{}", EventType::HsDesc), "HS_DESC");
2370 assert_eq!(format!("{}", EventType::HsDescContent), "HS_DESC_CONTENT");
2371 assert_eq!(
2372 format!("{}", EventType::NetworkLiveness),
2373 "NETWORK_LIVENESS"
2374 );
2375 assert_eq!(format!("{}", EventType::PtLog), "PT_LOG");
2376 assert_eq!(format!("{}", EventType::PtStatus), "PT_STATUS");
2377 }
2378
2379 #[test]
2380 fn test_status_type_display() {
2381 assert_eq!(format!("{}", StatusType::General), "GENERAL");
2382 assert_eq!(format!("{}", StatusType::Client), "CLIENT");
2383 assert_eq!(format!("{}", StatusType::Server), "SERVER");
2384 }
2385
2386 #[test]
2387 fn test_connection_type_display() {
2388 assert_eq!(format!("{}", ConnectionType::Or), "OR");
2389 assert_eq!(format!("{}", ConnectionType::Dir), "DIR");
2390 assert_eq!(format!("{}", ConnectionType::Exit), "EXIT");
2391 }
2392
2393 #[test]
2394 fn test_token_bucket_display() {
2395 assert_eq!(format!("{}", TokenBucket::Global), "GLOBAL");
2396 assert_eq!(format!("{}", TokenBucket::Relay), "RELAY");
2397 assert_eq!(format!("{}", TokenBucket::OrConn), "ORCONN");
2398 }
2399
2400 #[test]
2401 fn test_auth_descriptor_action_display() {
2402 assert_eq!(format!("{}", AuthDescriptorAction::Accepted), "ACCEPTED");
2403 assert_eq!(format!("{}", AuthDescriptorAction::Dropped), "DROPPED");
2404 assert_eq!(format!("{}", AuthDescriptorAction::Rejected), "REJECTED");
2405 }
2406
2407 #[test]
2408 fn test_bridge_distribution_display() {
2409 assert_eq!(format!("{}", BridgeDistribution::Any), "any");
2410 assert_eq!(format!("{}", BridgeDistribution::Https), "https");
2411 assert_eq!(format!("{}", BridgeDistribution::Email), "email");
2412 assert_eq!(format!("{}", BridgeDistribution::Moat), "moat");
2413 assert_eq!(format!("{}", BridgeDistribution::Hyphae), "hyphae");
2414 }
2415
2416 #[test]
2417 fn test_error_display() {
2418 let err = Error::Protocol("test error".to_string());
2419 assert!(format!("{}", err).contains("test error"));
2420
2421 let err = Error::OperationFailed {
2422 code: "500".to_string(),
2423 message: "failed".to_string(),
2424 };
2425 assert!(format!("{}", err).contains("500"));
2426 assert!(format!("{}", err).contains("failed"));
2427
2428 let err = Error::Parse {
2429 location: "line 1".to_string(),
2430 reason: "invalid".to_string(),
2431 };
2432 assert!(format!("{}", err).contains("line 1"));
2433 assert!(format!("{}", err).contains("invalid"));
2434
2435 let err = Error::Download {
2436 url: "http://example.com".to_string(),
2437 reason: "timeout".to_string(),
2438 };
2439 assert!(format!("{}", err).contains("example.com"));
2440
2441 let err = Error::DownloadTimeout {
2442 url: "http://example.com".to_string(),
2443 };
2444 assert!(format!("{}", err).contains("example.com"));
2445
2446 let err = Error::Timeout;
2447 assert!(format!("{}", err).contains("timeout"));
2448
2449 let err = Error::SocketClosed;
2450 assert!(format!("{}", err).contains("closed"));
2451
2452 let err = Error::DescriptorUnavailable("test".to_string());
2453 assert!(format!("{}", err).contains("test"));
2454
2455 let err = Error::CircuitExtensionFailed("test".to_string());
2456 assert!(format!("{}", err).contains("test"));
2457
2458 let err = Error::UnsatisfiableRequest("test".to_string());
2459 assert!(format!("{}", err).contains("test"));
2460
2461 let err = Error::InvalidRequest("test".to_string());
2462 assert!(format!("{}", err).contains("test"));
2463
2464 let err = Error::InvalidArguments("test".to_string());
2465 assert!(format!("{}", err).contains("test"));
2466 }
2467
2468 #[test]
2469 fn test_auth_error_display() {
2470 let err = AuthError::NoMethods;
2471 assert!(format!("{}", err).contains("no authentication"));
2472
2473 let err = AuthError::IncorrectPassword;
2474 assert!(format!("{}", err).contains("password"));
2475
2476 let err = AuthError::CookieUnreadable("path".to_string());
2477 assert!(format!("{}", err).contains("path"));
2478
2479 let err = AuthError::IncorrectCookie;
2480 assert!(format!("{}", err).contains("cookie"));
2481
2482 let err = AuthError::IncorrectCookieSize;
2483 assert!(format!("{}", err).contains("cookie"));
2484
2485 let err = AuthError::ChallengeFailed;
2486 assert!(format!("{}", err).contains("challenge"));
2487
2488 let err = AuthError::ChallengeUnsupported;
2489 assert!(format!("{}", err).contains("challenge"));
2490
2491 let err = AuthError::SecurityFailure;
2492 assert!(format!("{}", err).contains("security"));
2493
2494 let err = AuthError::MissingPassword;
2495 assert!(format!("{}", err).contains("password"));
2496
2497 let err = AuthError::UnrecognizedMethods(vec!["test".to_string()]);
2498 assert!(format!("{}", err).contains("test"));
2499
2500 let err = AuthError::IncorrectSocketType;
2501 assert!(format!("{}", err).contains("socket"));
2502 }
2503
2504 #[test]
2505 fn test_enum_equality() {
2506 assert_eq!(Runlevel::Debug, Runlevel::Debug);
2507 assert_ne!(Runlevel::Debug, Runlevel::Info);
2508
2509 assert_eq!(Signal::Reload, Signal::Reload);
2510 assert_ne!(Signal::Reload, Signal::Shutdown);
2511
2512 assert_eq!(Flag::Exit, Flag::Exit);
2513 assert_ne!(Flag::Exit, Flag::Guard);
2514 }
2515
2516 #[test]
2517 fn test_enum_hash() {
2518 use std::collections::HashSet;
2519
2520 let mut set = HashSet::new();
2521 set.insert(Runlevel::Debug);
2522 set.insert(Runlevel::Info);
2523 assert!(set.contains(&Runlevel::Debug));
2524 assert!(!set.contains(&Runlevel::Warn));
2525
2526 let mut set = HashSet::new();
2527 set.insert(Signal::Newnym);
2528 assert!(set.contains(&Signal::Newnym));
2529 }
2530
2531 #[test]
2532 fn test_enum_clone() {
2533 let r = Runlevel::Debug;
2534 let r2 = r;
2535 assert_eq!(r, r2);
2536
2537 let s = Signal::Newnym;
2538 let s2 = s;
2539 assert_eq!(s, s2);
2540 }
2541
2542 #[test]
2543 fn test_enum_debug() {
2544 assert!(format!("{:?}", Runlevel::Debug).contains("Debug"));
2545 assert!(format!("{:?}", Signal::Newnym).contains("Newnym"));
2546 assert!(format!("{:?}", Flag::Exit).contains("Exit"));
2547 }
2548}