1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::connections::ServiceError::{ClosedNormally, ConnectionFailed};
use crate::connections::{Connection, InboundConnection, OutboundConnection, ServiceError};
use crate::primitives::identity::Identity;
use std::net::TcpListener;
use std::sync::Arc;
use std::thread::{spawn, JoinHandle};
use socks::Socks5Stream;
use socks::TargetAddr::Domain;
pub struct NoListenService(());
pub struct ApplicationListenService(());
pub struct Service<ListenService> {
identity: Arc<Identity>,
socks_port: u16,
listen_service: ListenService,
}
impl<ListenService> Service<ListenService> {
pub fn connect<F>(&mut self, hostname: &str, application: F) -> Result<(), ServiceError>
where
F: FnOnce(Connection<OutboundConnection>) + Send + Clone + 'static,
{
let conn = Socks5Stream::connect(format!("127.0.0.1:{}", self.socks_port), Domain(format!("{}.onion", hostname), 9878));
match conn {
Ok(conn) => {
let application = application.clone();
spawn(move || application(Connection::<OutboundConnection>::new_outbound(conn.into_inner())));
Ok(())
}
Err(err) => Err(ConnectionFailed(err.to_string())),
}
}
}
impl Service<NoListenService> {
pub fn init(identity: Arc<Identity>, socks_port: u16) -> Service<NoListenService> {
Service {
identity,
socks_port,
listen_service: NoListenService(()),
}
}
pub fn listen<F>(self, port: u16, application: F) -> Result<Service<JoinHandle<ServiceError>>, ServiceError>
where
F: FnOnce(Connection<InboundConnection>) + Send + Clone + 'static,
{
let jh = spawn(move || {
let listener = TcpListener::bind(format!("127.0.0.1:{}", port));
match listener {
Ok(listener) => {
for stream in listener.incoming() {
match stream {
Ok(conn) => {
let application = application.clone();
spawn(move || application(Connection::<InboundConnection>::new_inbound(conn)));
}
Err(_) => {}
}
}
ClosedNormally
}
Err(err) => ServiceError::ListenFailed(err.to_string()),
}
});
Ok(Service {
identity: self.identity,
socks_port: self.socks_port,
listen_service: jh,
})
}
}
impl Service<JoinHandle<ServiceError>> {
pub fn close(self) {
let result = self.listen_service.join();
match result {
Ok(err) => eprintln!("{:?}", err),
_ => eprintln!("Error joining listen thread"),
}
}
}
#[cfg(test)]
mod tests {
use crate::connections::service::Service;
use crate::primitives::identity::Identity;
use ed25519_dalek::SecretKey;
use rand::rngs::OsRng;
#[test]
fn service_state() {
let mut csprng = OsRng {};
let keypair = ed25519_dalek::Keypair::generate(&mut csprng);
let _secret_key = SecretKey::from_bytes(&keypair.secret.to_bytes());
let identity = Identity::initialize(keypair);
let _service = Service::init(identity, 9051);
}
#[test]
fn service_lifetime() {
let mut csprng = OsRng {};
let keypair = ed25519_dalek::Keypair::generate(&mut csprng);
let _secret_key = SecretKey::from_bytes(&keypair.secret.to_bytes());
let identity = Identity::initialize(keypair);
let _service = Service::init(identity, 9051);
}
}