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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//! tx3 p2p communications
//!
//! [](http://holochain.org/)
//! [](https://forum.holochain.org)
//! [](https://chat.holochain.org)
//!
//! [](https://www.apache.org/licenses/LICENSE-2.0)
//!
//! ### An interim Holochain networking solution
//!
//! Holochain has experimented with many different networking solutions.
//! We mainly have our eye on webrtc, due to the benefits of direct STUN
//! p2p negotiation, with fallback TURN relaying for non-symmetric network
//! cases. We've also run on QUIC. For the time being, however, none of these
//! solutions have proven mature enough in the rust ecosystem to get us
//! the performance, reliability, and end-to-end encryption we need.
//!
//! Tx3 provides a very simple interim stack: TLS over TCP. A relay server
//! splices raw TCP streams together providing addressability for clients
//! behind NATs. The clients negotiate end-to-end TLS over these spliced
//! streams, ensuring the relay server or any MITM has no access to the
//! plaintext. (If you want to learn more about the relay protocol, see
//! the [Tx3Relay] docs.)
//!
//! ```text
//! +-------+
//! | relay | (TCP splicing)
//! +-------+
//! / \
//! / \ (TLS over TCP)
//! / \
//! +-------+ +-------+
//! | node1 | | node2 |
//! +-------+ +-------+
//! ```
//!
//! As with many p2p solutions, ensuring you are talking to who you think you
//! are is left to other layers of the application. But tx3 tries to make
//! this simple by including the TLS certificate digest in the url, so that
//! holochain can easily provide signature verification.
//!
//! E.g.
//!
//! ```text
//! tx3-rst://127.0.0.1:38141/EHoKZ3-8R520Unp3vr4xeP6ogYAqoZ-em8lm-rMlwhw
//! ```
//!
//! Nodes that are directly addressable, or can configure port-forwarding are
//! welcome and encouraged to make direct connections, instead of relaying.
//!
//! ```text
//! +-------+ (TLS over TCP) +-------+
//! | node1 |----------------| node2 |
//! +-------+ +-------+
//! ```
//!
//! ### Run a locally addressable tx3 node
//!
//! ```
//! # #[tokio::main]
//! # async fn main() {
//! let tx3_config = tx3::Tx3Config::new().with_bind("tx3-st://127.0.0.1:0");
//!
//! let (node, _inbound_con) = tx3::Tx3Node::new(tx3_config).await.unwrap();
//!
//! println!("listening on addresses: {:#?}", node.local_addrs());
//! # }
//! ```
//!
//! ### Run an in-process relay node
//!
//! Note: Unless you're writing test code, you probably want the executable.
//! See below for `tx3-relay` commandline flags and options.
//!
//! ```
//! # #[tokio::main]
//! # async fn main() {
//! let tx3_relay_config = tx3::Tx3RelayConfig::new()
//! .with_bind("tx3-rst://127.0.0.1:0");
//! let relay = tx3::Tx3Relay::new(tx3_relay_config).await.unwrap();
//!
//! println!("relay listening on addresses: {:#?}", relay.local_addrs());
//! # }
//! ```
//!
//! ### Run a tx3 node relayed over the given relay address
//!
//! ```
//! # #[tokio::main]
//! # async fn main() {
//! # let tx3_relay_config = tx3::Tx3RelayConfig::new()
//! # .with_bind("tx3-rst://127.0.0.1:0");
//! # let relay = tx3::Tx3Relay::new(tx3_relay_config).await.unwrap();
//! # let relay_addr = relay.local_addrs()[0].to_owned();
//! # let relay_addr = &relay_addr;
//! // set relay_addr to your relay address, something like:
//! // let relay_addr = "tx3-rst://127.0.0.1:38141/EHoKZ3-8R520Unp3vr4xeP6ogYAqoZ-em8lm-rMlwhw";
//!
//! let tx3_config = tx3::Tx3Config::new().with_bind(relay_addr);
//!
//! let (node, _inbound_con) = tx3::Tx3Node::new(tx3_config).await.unwrap();
//!
//! println!("listening on addresses: {:#?}", node.local_addrs());
//! # }
//! ```
//!
//! ### Connect and receive connections
//!
//! ```
//! # #[tokio::main]
//! # async fn main() {
//! # use tokio::io::AsyncReadExt;
//! # use tokio::io::AsyncWriteExt;
//! // create a listening node
//! let tx3_config = tx3::Tx3Config::new().with_bind("tx3-st://127.0.0.1:0");
//! let (node1, mut recv1) = tx3::Tx3Node::new(tx3_config).await.unwrap();
//! let addr1 = node1.local_addrs()[0].to_owned();
//!
//! // listen for incoming connections
//! let task = tokio::task::spawn(async move {
//! let acceptor = recv1.recv().await.unwrap();
//!
//! // in production code we might want to spawn this so we can
//! // receive more connections, handling their handshakes in paralel
//! let mut in_con = acceptor.accept().await.unwrap();
//!
//! // make sure we can read data
//! let mut got = [0; 5];
//! in_con.read_exact(&mut got).await.unwrap();
//! assert_eq!(b"hello", &got[..]);
//!
//! // make sure we can write data
//! in_con.write_all(b"world").await.unwrap();
//! in_con.shutdown().await.unwrap();
//! });
//!
//! // create an outgoing-only node
//! let tx3_config = tx3::Tx3Config::new();
//! let (node2, _) = tx3::Tx3Node::new(tx3_config).await.unwrap();
//!
//! // connect from our outgoing node to our receive node
//! let mut out_con = node2.connect(&addr1).await.unwrap();
//!
//! // make sure we can write data
//! out_con.write_all(b"hello").await.unwrap();
//! out_con.shutdown().await.unwrap();
//!
//! // make sure we can read data
//! let mut got = [0; 5];
//! out_con.read_exact(&mut got).await.unwrap();
//! assert_eq!(b"world", &got[..]);
//!
//! // make sure our receiver task shuts down cleanly
//! task.await.unwrap();
//! # }
//! ```
/// Tx3 helper until `std::io::Error::other()` is stablized
use Result;
pub
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;