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