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