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}