1
//! Client-specific types and implementation.
2

            
3
pub mod channel;
4
pub mod circuit;
5
pub mod stream;
6

            
7
#[cfg(feature = "rpc")]
8
pub mod rpc;
9

            
10
#[cfg(feature = "send-control-msg")]
11
pub(crate) mod msghandler;
12
pub(crate) mod reactor;
13

            
14
use derive_deftly::Deftly;
15
use oneshot_fused_workaround as oneshot;
16
use std::net::IpAddr;
17
use std::sync::Arc;
18
use tracing::instrument;
19

            
20
use crate::circuit::UniqId;
21
use crate::circuit::circhop::ReactorStreamComponents;
22
#[cfg(feature = "circ-padding-manual")]
23
pub use crate::client::circuit::padding::{
24
    CircuitPadder, CircuitPadderConfig, CircuitPadderConfigError,
25
};
26
use crate::client::stream::{
27
    DataStream, OutboundDataCmdChecker, ResolveCmdChecker, ResolveStream, StreamParameters,
28
};
29
use crate::congestion::sendme::StreamRecvWindow;
30
use crate::crypto::cell::HopNum;
31
use crate::memquota::{SpecificAccount as _, StreamAccount};
32
use crate::stream::STREAM_READER_BUFFER;
33
use crate::stream::cmdcheck::AnyCmdChecker;
34
use crate::stream::flow_ctrl::xon_xoff::reader::XonXoffReaderCtrl;
35
use crate::stream::{RECV_WINDOW_INIT, StreamComponents, StreamReceiver, StreamTarget, Tunnel};
36
use crate::{Error, ResolveError, Result};
37
use circuit::{ClientCirc, Path};
38
use reactor::{CtrlCmd, CtrlMsg, FlowCtrlMsg, MetaCellHandler};
39

            
40
use tor_cell::relaycell::StreamId;
41
use tor_cell::relaycell::flow_ctrl::XonKBpsEwma;
42
use tor_cell::relaycell::msg::{AnyRelayMsg, Begin, Resolve, Resolved, ResolvedVal};
43
use tor_error::bad_api_usage;
44
use tor_linkspec::OwnedChanTarget;
45
use tor_memquota::derive_deftly_template_HasMemoryCost;
46
use tor_memquota::mq_queue::{ChannelSpec as _, MpscSpec};
47

            
48
#[cfg(feature = "hs-service")]
49
use crate::stream::{IncomingCmdChecker, IncomingStream, StreamReqInfo};
50

            
51
#[cfg(feature = "send-control-msg")]
52
use msghandler::{MsgHandler, UserMsgHandler};
53

            
54
/// Handle to use during an ongoing protocol exchange with a circuit's last hop
55
///
56
/// This is obtained from [`ClientTunnel::start_conversation`],
57
/// and used to send messages to the last hop relay.
58
//
59
// TODO(conflux): this should use ClientTunnel, and it should be moved into
60
// the tunnel module.
61
#[cfg(feature = "send-control-msg")]
62
pub struct Conversation<'r>(&'r ClientTunnel);
63

            
64
#[cfg(feature = "send-control-msg")]
65
impl Conversation<'_> {
66
    /// Send a protocol message as part of an ad-hoc exchange
67
    ///
68
    /// Responses are handled by the `UserMsgHandler` set up
69
    /// when the `Conversation` was created.
70
    pub async fn send_message(&self, msg: tor_cell::relaycell::msg::AnyRelayMsg) -> Result<()> {
71
        self.send_internal(Some(msg), None).await
72
    }
73

            
74
    /// Send a `SendMsgAndInstallHandler` to the reactor and wait for the outcome
75
    ///
76
    /// The guts of `start_conversation` and `Conversation::send_msg`
77
    pub(crate) async fn send_internal(
78
        &self,
79
        msg: Option<tor_cell::relaycell::msg::AnyRelayMsg>,
80
        handler: Option<Box<dyn MetaCellHandler + Send + 'static>>,
81
    ) -> Result<()> {
82
        let msg = msg.map(|msg| tor_cell::relaycell::AnyRelayMsgOuter::new(None, msg));
83
        let (sender, receiver) = oneshot::channel();
84

            
85
        let ctrl_msg = CtrlMsg::SendMsgAndInstallHandler {
86
            msg,
87
            handler,
88
            sender,
89
        };
90
        self.0
91
            .circ
92
            .control
93
            .unbounded_send(ctrl_msg)
94
            .map_err(|_| Error::CircuitClosed)?;
95

            
96
        receiver.await.map_err(|_| Error::CircuitClosed)?
97
    }
98
}
99

            
100
/// A low-level client tunnel API.
101
///
102
/// This is a communication channel to the tunnel reactor, which manages 1 or more circuits.
103
///
104
/// Note: the tor-circmgr crates wrap this type in specialized *Tunnel types exposing only the
105
/// desired subset of functionality depending on purpose and path size.
106
///
107
/// Some API calls are for single path and some for multi path. A check with the underlying reactor
108
/// is done preventing for instance multi path calls to be used on a single path. Top level types
109
/// should prevent this and thus this object should never be used directly.
110
#[derive(Debug)]
111
#[cfg_attr(
112
    feature = "rpc",
113
    derive(derive_deftly::Deftly),
114
    derive_deftly(tor_rpcbase::templates::Object)
115
)]
116
#[allow(dead_code)] // TODO(conflux)
117
pub struct ClientTunnel {
118
    /// The underlying handle to the reactor.
119
    circ: ClientCirc,
120
}
121

            
122
impl ClientTunnel {
123
    /// Return a handle to the `ClientCirc` of this `ClientTunnel`, if the tunnel is a single
124
    /// circuit tunnel.
125
    ///
126
    /// Returns an error if the tunnel has more than one circuit.
127
218
    pub fn as_single_circ(&self) -> Result<&ClientCirc> {
128
218
        if self.circ.is_multi_path {
129
2
            Err(bad_api_usage!("Single circuit getter on multi path tunnel"))?;
130
216
        }
131
216
        Ok(&self.circ)
132
218
    }
133

            
134
    /// Return the channel target of the first hop.
135
    ///
136
    /// Can only be used for single path tunnel.
137
    pub fn first_hop(&self) -> Result<OwnedChanTarget> {
138
        self.as_single_circ()?.first_hop()
139
    }
140

            
141
    /// Return true if the circuit reactor is closed meaning the circuit is unusable for both
142
    /// receiving or sending.
143
64
    pub fn is_closed(&self) -> bool {
144
64
        self.circ.is_closing()
145
64
    }
146

            
147
    /// Return a [`TargetHop`] representing precisely the last hop of the circuit as in set as a
148
    /// HopLocation with its id and hop number.
149
    ///
150
    /// Return an error if there is no last hop.
151
    pub fn last_hop(&self) -> Result<TargetHop> {
152
        let uniq_id = self.unique_id();
153
        let hop_num = self
154
            .circ
155
            .mutable
156
            .last_hop_num(uniq_id)?
157
            .ok_or_else(|| bad_api_usage!("no last hop"))?;
158
        Ok((uniq_id, hop_num).into())
159
    }
160

            
161
    /// Return a description of the last hop of the tunnel.
162
    ///
163
    /// Return None if the last hop is virtual; return an error
164
    /// if the tunnel has no circuits, or all of its circuits are zero length.
165
    ///
166
    ///
167
    /// # Panics
168
    ///
169
    /// Panics if there is no last hop.  (This should be impossible outside of
170
    /// the tor-proto crate, but within the crate it's possible to have a
171
    /// circuit with no hops.)
172
    pub fn last_hop_info(&self) -> Result<Option<OwnedChanTarget>> {
173
        self.circ.last_hop_info()
174
    }
175

            
176
    /// Return the number of hops this tunnel as. Fail for a multi path.
177
48
    pub fn n_hops(&self) -> Result<usize> {
178
48
        self.as_single_circ()?.n_hops()
179
48
    }
180

            
181
    /// Return the [`Path`] objects describing all the hops
182
    /// of all the circuits in this tunnel.
183
    pub fn all_paths(&self) -> Vec<Arc<Path>> {
184
        self.circ.all_paths()
185
    }
186

            
187
    /// Return a representation of the Paths for all the circuits in this tunnel,
188
    /// as a map from each circuits' UniqId to its path.
189
    ///
190
    /// This is only exposed for the RPC subsystem, where it is documented that the
191
    /// format of `UniqId` is not stable.
192
    #[cfg(feature = "rpc")]
193
    pub(crate) fn tagged_paths(&self) -> std::collections::HashMap<UniqId, Arc<Path>> {
194
        self.circ.mutable.tagged_paths()
195
    }
196

            
197
    /// Return a process-unique identifier for this tunnel.
198
    ///
199
    /// Returns the reactor unique ID of the main reactor.
200
64
    pub fn unique_id(&self) -> UniqId {
201
64
        self.circ.unique_id()
202
64
    }
203

            
204
    /// Return the time at which this tunnel last had any open streams.
205
    ///
206
    /// Returns `None` if this tunnel has never had any open streams,
207
    /// or if it currently has open streams.
208
    ///
209
    /// NOTE that the Instant returned by this method is not affected by
210
    /// any runtime mocking; it is the output of an ordinary call to
211
    /// `Instant::now()`.
212
    pub async fn disused_since(&self) -> Result<Option<web_time_compat::Instant>> {
213
        self.circ.disused_since().await
214
    }
215

            
216
    /// Return a future that will resolve once the underlying circuit reactor has closed.
217
    ///
218
    /// Note that this method does not itself cause the tunnel to shut down.
219
    pub fn wait_for_close(
220
        self: &Arc<Self>,
221
    ) -> impl futures::Future<Output = ()> + Send + Sync + 'static + use<> {
222
        self.circ.wait_for_close()
223
    }
224

            
225
    /// Single-path tunnel only. Multi path onion service is not supported yet.
226
    ///
227
    /// Tell this tunnel to begin allowing the final hop of the tunnel to try
228
    /// to create new Tor streams, and to return those pending requests in an
229
    /// asynchronous stream.
230
    ///
231
    /// Ordinarily, these requests are rejected.
232
    ///
233
    /// There can only be one [`Stream`](futures::Stream) of this type created on a given tunnel.
234
    /// If a such a [`Stream`](futures::Stream) already exists, this method will return
235
    /// an error.
236
    ///
237
    /// After this method has been called on a tunnel, the tunnel is expected
238
    /// to receive requests of this type indefinitely, until it is finally closed.
239
    /// If the `Stream` is dropped, the next request on this tunnel will cause it to close.
240
    ///
241
    /// Only onion services (and eventually) exit relays should call this
242
    /// method.
243
    //
244
    // TODO: Someday, we might want to allow a stream request handler to be
245
    // un-registered.  However, nothing in the Tor protocol requires it.
246
    //
247
    // Any incoming request handlers installed on the other circuits
248
    // (which are shutdown using CtrlCmd::ShutdownAndReturnCircuit)
249
    // will be discarded (along with the reactor of that circuit)
250
    #[cfg(feature = "hs-service")]
251
    #[allow(unreachable_code, unused_variables)] // TODO(conflux)
252
32
    pub async fn allow_stream_requests<'a, FILT>(
253
32
        self: &Arc<Self>,
254
32
        allow_commands: &'a [tor_cell::relaycell::RelayCmd],
255
32
        hop: TargetHop,
256
32
        filter: FILT,
257
32
    ) -> Result<impl futures::Stream<Item = IncomingStream> + use<'a, FILT>>
258
32
    where
259
32
        FILT: crate::stream::IncomingStreamRequestFilter + 'a,
260
32
    {
261
        use futures::stream::StreamExt;
262

            
263
        /// The size of the channel receiving IncomingStreamRequestContexts.
264
        const INCOMING_BUFFER: usize = STREAM_READER_BUFFER;
265

            
266
        // TODO(#2002): support onion service conflux
267
32
        let circ = self.as_single_circ().map_err(tor_error::into_internal!(
268
            "Cannot allow stream requests on a multi-path tunnel"
269
2
        ))?;
270

            
271
30
        let time_prov = circ.time_provider.clone();
272
30
        let cmd_checker = IncomingCmdChecker::new_any(allow_commands);
273
30
        let (incoming_sender, incoming_receiver) = MpscSpec::new(INCOMING_BUFFER)
274
30
            .new_mq(time_prov.clone(), circ.memquota.as_raw_account())?;
275
30
        let (tx, rx) = oneshot::channel();
276

            
277
30
        circ.command
278
30
            .unbounded_send(CtrlCmd::AwaitStreamRequest {
279
30
                cmd_checker,
280
30
                incoming_sender,
281
30
                hop,
282
30
                done: tx,
283
30
                filter: Box::new(filter),
284
30
            })
285
30
            .map_err(|_| Error::CircuitClosed)?;
286

            
287
        // Check whether the AwaitStreamRequest was processed successfully.
288
30
        rx.await.map_err(|_| Error::CircuitClosed)??;
289

            
290
24
        let allowed_hop_loc: HopLocation = match hop {
291
24
            TargetHop::Hop(loc) => Some(loc),
292
            _ => None,
293
        }
294
24
        .ok_or_else(|| bad_api_usage!("Expected TargetHop with HopLocation"))?;
295

            
296
24
        let tunnel = self.clone();
297
24
        Ok(incoming_receiver.map(move |req_ctx| {
298
            let StreamReqInfo {
299
18
                req,
300
18
                stream_id,
301
18
                hop,
302
                stream_components:
303
                    ReactorStreamComponents {
304
18
                        stream_inbound_rx,
305
18
                        stream_outbound_tx,
306
18
                        rate_limit_rx,
307
18
                        drain_rate_request_rx,
308
                    },
309
18
                memquota,
310
18
                relay_cell_format,
311
18
            } = req_ctx;
312

            
313
            // We already enforce this in handle_incoming_stream_request; this
314
            // assertion is just here to make sure that we don't ever
315
            // accidentally remove or fail to enforce that check, since it is
316
            // security-critical.
317
18
            assert_eq!(Some(allowed_hop_loc), hop);
318

            
319
            // TODO(#2002): figure out what this is going to look like
320
            // for onion services (perhaps we should forbid this function
321
            // from being called on a multipath circuit?)
322
            //
323
            // See also:
324
            // https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/3002#note_3200937
325
18
            let target = StreamTarget {
326
18
                tunnel: Tunnel::Client(Arc::clone(&tunnel)),
327
18
                tx: stream_outbound_tx,
328
18
                hop: Some(allowed_hop_loc),
329
18
                stream_id,
330
18
                relay_cell_format,
331
18
                rate_limit_stream: rate_limit_rx,
332
18
            };
333

            
334
            // can be used to build a reader that supports XON/XOFF flow control
335
18
            let xon_xoff_reader_ctrl =
336
18
                XonXoffReaderCtrl::new(drain_rate_request_rx, target.clone());
337

            
338
18
            let reader = StreamReceiver {
339
18
                target: target.clone(),
340
18
                receiver: stream_inbound_rx,
341
18
                recv_window: StreamRecvWindow::new(RECV_WINDOW_INIT),
342
18
                ended: false,
343
18
            };
344

            
345
18
            let components = StreamComponents {
346
18
                stream_receiver: reader,
347
18
                target,
348
18
                memquota,
349
18
                xon_xoff_reader_ctrl,
350
18
            };
351

            
352
18
            IncomingStream::new(time_prov.clone(), req, components)
353
18
        }))
354
32
    }
355

            
356
    /// Single and Multi path helper, used to begin a stream.
357
    ///
358
    /// This function allocates a stream ID, and sends the message
359
    /// (like a BEGIN or RESOLVE), but doesn't wait for a response.
360
    ///
361
    /// The caller will typically want to see the first cell in response,
362
    /// to see whether it is e.g. an END or a CONNECTED.
363
48
    async fn begin_stream_impl(
364
48
        self: &Arc<Self>,
365
48
        begin_msg: AnyRelayMsg,
366
48
        cmd_checker: AnyCmdChecker,
367
48
    ) -> Result<StreamComponents> {
368
        // TODO: Possibly this should take a hop, rather than just
369
        // assuming it's the last hop.
370
48
        let hop = TargetHop::LastHop;
371

            
372
48
        let memquota = StreamAccount::new(self.circ.mq_account())?;
373
48
        let (tx, rx) = oneshot::channel();
374

            
375
48
        self.circ
376
48
            .control
377
48
            .unbounded_send(CtrlMsg::BeginStream {
378
48
                hop,
379
48
                message: begin_msg,
380
48
                memquota: memquota.clone(),
381
48
                done: tx,
382
48
                cmd_checker,
383
48
            })
384
48
            .map_err(|_| Error::CircuitClosed)?;
385

            
386
48
        let (stream_id, hop, relay_cell_format, stream_components) =
387
48
            rx.await.map_err(|_| Error::CircuitClosed)??;
388

            
389
        // Destructure so that we don't forget to use any fields.
390
        let ReactorStreamComponents {
391
48
            stream_inbound_rx,
392
48
            stream_outbound_tx,
393
48
            rate_limit_rx,
394
48
            drain_rate_request_rx,
395
48
        } = stream_components;
396

            
397
48
        let target = StreamTarget {
398
48
            tunnel: Tunnel::Client(self.clone()),
399
48
            tx: stream_outbound_tx,
400
48
            hop: Some(hop),
401
48
            stream_id,
402
48
            relay_cell_format,
403
48
            rate_limit_stream: rate_limit_rx,
404
48
        };
405

            
406
        // can be used to build a reader that supports XON/XOFF flow control
407
48
        let xon_xoff_reader_ctrl = XonXoffReaderCtrl::new(drain_rate_request_rx, target.clone());
408

            
409
48
        let stream_receiver = StreamReceiver {
410
48
            target: target.clone(),
411
48
            receiver: stream_inbound_rx,
412
48
            recv_window: StreamRecvWindow::new(RECV_WINDOW_INIT),
413
48
            ended: false,
414
48
        };
415

            
416
48
        let components = StreamComponents {
417
48
            stream_receiver,
418
48
            target,
419
48
            memquota,
420
48
            xon_xoff_reader_ctrl,
421
48
        };
422

            
423
48
        Ok(components)
424
48
    }
425

            
426
    /// Install a [`CircuitPadder`] at the listed `hop`.
427
    ///
428
    /// Replaces any previous padder installed at that hop.
429
    #[cfg(feature = "circ-padding-manual")]
430
    pub async fn start_padding_at_hop(
431
        self: &Arc<Self>,
432
        hop: HopLocation,
433
        padder: CircuitPadder,
434
    ) -> Result<()> {
435
        self.circ.set_padder_impl(hop, Some(padder)).await
436
    }
437

            
438
    /// Remove any [`CircuitPadder`] at the listed `hop`.
439
    ///
440
    /// Does nothing if there was not a padder installed there.
441
    #[cfg(feature = "circ-padding-manual")]
442
    pub async fn stop_padding_at_hop(self: &Arc<Self>, hop: HopLocation) -> Result<()> {
443
        self.circ.set_padder_impl(hop, None).await
444
    }
445

            
446
    /// Start a DataStream (anonymized connection) to the given
447
    /// address and port, using a BEGIN cell.
448
48
    async fn begin_data_stream(
449
48
        self: &Arc<Self>,
450
48
        msg: AnyRelayMsg,
451
48
        optimistic: bool,
452
48
    ) -> Result<DataStream> {
453
48
        let components = self
454
48
            .begin_stream_impl(msg, OutboundDataCmdChecker::new_any())
455
48
            .await?;
456

            
457
        let StreamComponents {
458
48
            stream_receiver,
459
48
            target,
460
48
            memquota,
461
48
            xon_xoff_reader_ctrl,
462
48
        } = components;
463

            
464
48
        let mut stream = DataStream::new(
465
48
            self.circ.time_provider.clone(),
466
48
            stream_receiver,
467
48
            xon_xoff_reader_ctrl,
468
48
            target,
469
48
            memquota,
470
        );
471
48
        if !optimistic {
472
42
            stream.wait_for_connection().await?;
473
6
        }
474
48
        Ok(stream)
475
48
    }
476

            
477
    /// Single and multi path helper.
478
    ///
479
    /// Start a stream to the given address and port, using a BEGIN
480
    /// cell.
481
    ///
482
    /// The use of a string for the address is intentional: you should let
483
    /// the remote Tor relay do the hostname lookup for you.
484
    #[instrument(level = "trace", skip_all)]
485
42
    pub async fn begin_stream(
486
42
        self: &Arc<Self>,
487
42
        target: &str,
488
42
        port: u16,
489
42
        parameters: Option<StreamParameters>,
490
42
    ) -> Result<DataStream> {
491
        let parameters = parameters.unwrap_or_default();
492
        let begin_flags = parameters.begin_flags();
493
        let optimistic = parameters.is_optimistic();
494
        let target = if parameters.suppressing_hostname() {
495
            ""
496
        } else {
497
            target
498
        };
499
        let beginmsg = Begin::new(target, port, begin_flags)
500
            .map_err(|e| Error::from_cell_enc(e, "begin message"))?;
501
        self.begin_data_stream(beginmsg.into(), optimistic).await
502
42
    }
503

            
504
    /// Start a new stream to the last relay in the tunnel, using
505
    /// a BEGIN_DIR cell.
506
6
    pub async fn begin_dir_stream(self: Arc<Self>) -> Result<DataStream> {
507
        // Note that we always open begindir connections optimistically.
508
        // Since they are local to a relay that we've already authenticated
509
        // with and built a tunnel to, there should be no additional checks
510
        // we need to perform to see whether the BEGINDIR will succeed.
511
6
        self.begin_data_stream(AnyRelayMsg::BeginDir(Default::default()), true)
512
6
            .await
513
6
    }
514

            
515
    /// Perform a DNS lookup, using a RESOLVE cell with the last relay
516
    /// in this tunnel.
517
    ///
518
    /// Returns all the addresses from the RESOLVED response,
519
    /// without performing any filtering.
520
    /// Most callers will want filter out the local and non-routable addresses
521
    /// before using the result.
522
    ///
523
    /// Note that this function does not check for timeouts; that's
524
    /// the caller's responsibility.
525
    pub async fn resolve(self: &Arc<Self>, hostname: &str) -> Result<Vec<IpAddr>> {
526
        let resolve_msg = Resolve::new(hostname);
527

            
528
        let resolved_msg = self.try_resolve(resolve_msg).await?;
529

            
530
        resolved_msg
531
            .into_answers()
532
            .into_iter()
533
            .filter_map(|(val, _)| match resolvedval_to_result(val) {
534
                Ok(ResolvedVal::Ip(ip)) => Some(Ok(ip)),
535
                Ok(_) => None,
536
                Err(e) => Some(Err(e)),
537
            })
538
            .collect()
539
    }
540

            
541
    /// Perform a reverse DNS lookup, by sending a RESOLVE cell with
542
    /// the last relay on this tunnel.
543
    ///
544
    /// Does not perform any validation on `addr`.
545
    /// Most callers will want to avoid calling this function
546
    /// with a local or non-routable `addr`.
547
    ///
548
    /// Note that this function does not check for timeouts; that's
549
    /// the caller's responsibility.
550
    pub async fn resolve_ptr(self: &Arc<Self>, addr: IpAddr) -> Result<Vec<String>> {
551
        let resolve_ptr_msg = Resolve::new_reverse(&addr);
552

            
553
        let resolved_msg = self.try_resolve(resolve_ptr_msg).await?;
554

            
555
        resolved_msg
556
            .into_answers()
557
            .into_iter()
558
            .filter_map(|(val, _)| match resolvedval_to_result(val) {
559
                Ok(ResolvedVal::Hostname(v)) => Some(
560
                    String::from_utf8(v)
561
                        .map_err(|_| Error::StreamProto("Resolved Hostname was not utf-8".into())),
562
                ),
563
                Ok(_) => None,
564
                Err(e) => Some(Err(e)),
565
            })
566
            .collect()
567
    }
568

            
569
    /// Send an ad-hoc message to a given hop on the circuit, without expecting
570
    /// a reply.
571
    ///
572
    /// (If you want to handle one or more possible replies, see
573
    /// [`ClientTunnel::start_conversation`].)
574
    // TODO(conflux): Change this to use the ReactorHandle for the control commands.
575
    #[cfg(feature = "send-control-msg")]
576
    pub async fn send_raw_msg(
577
        &self,
578
        msg: tor_cell::relaycell::msg::AnyRelayMsg,
579
        hop: TargetHop,
580
    ) -> Result<()> {
581
        let (sender, receiver) = oneshot::channel();
582
        let ctrl_msg = CtrlMsg::SendMsg { hop, msg, sender };
583
        self.circ
584
            .control
585
            .unbounded_send(ctrl_msg)
586
            .map_err(|_| Error::CircuitClosed)?;
587

            
588
        receiver.await.map_err(|_| Error::CircuitClosed)?
589
    }
590

            
591
    /// Start an ad-hoc protocol exchange to the specified hop on this tunnel.
592
    ///
593
    /// To use this:
594
    ///
595
    ///  0. Create an inter-task channel you'll use to receive
596
    ///     the outcome of your conversation,
597
    ///     and bundle it into a [`UserMsgHandler`].
598
    ///
599
    ///  1. Call `start_conversation`.
600
    ///     This will install a your handler, for incoming messages,
601
    ///     and send the outgoing message (if you provided one).
602
    ///     After that, each message on the circuit
603
    ///     that isn't handled by the core machinery
604
    ///     is passed to your provided `reply_handler`.
605
    ///
606
    ///  2. Possibly call `send_msg` on the [`Conversation`],
607
    ///     from the call site of `start_conversation`,
608
    ///     possibly multiple times, from time to time,
609
    ///     to send further desired messages to the peer.
610
    ///
611
    ///  3. In your [`UserMsgHandler`], process the incoming messages.
612
    ///     You may respond by
613
    ///     sending additional messages
614
    ///     When the protocol exchange is finished,
615
    ///     `UserMsgHandler::handle_msg` should return
616
    ///     [`ConversationFinished`](reactor::MetaCellDisposition::ConversationFinished).
617
    ///
618
    /// If you don't need the `Conversation` to send followup messages,
619
    /// you may simply drop it,
620
    /// and rely on the responses you get from your handler,
621
    /// on the channel from step 0 above.
622
    /// Your handler will remain installed and able to process incoming messages
623
    /// until it returns `ConversationFinished`.
624
    ///
625
    /// (If you don't want to accept any replies at all, it may be
626
    /// simpler to use [`ClientTunnel::send_raw_msg`].)
627
    ///
628
    /// Note that it is quite possible to use this function to violate the tor
629
    /// protocol; most users of this API will not need to call it.  It is used
630
    /// to implement most of the onion service handshake.
631
    ///
632
    /// # Limitations
633
    ///
634
    /// Only one conversation may be active at any one time,
635
    /// for any one circuit.
636
    /// This generally means that this function should not be called
637
    /// on a tunnel which might be shared with anyone else.
638
    ///
639
    /// Likewise, it is forbidden to try to extend the tunnel,
640
    /// while the conversation is in progress.
641
    ///
642
    /// After the conversation has finished, the tunnel may be extended.
643
    /// Or, `start_conversation` may be called again;
644
    /// but, in that case there will be a gap between the two conversations,
645
    /// during which no `UserMsgHandler` is installed,
646
    /// and unexpected incoming messages would close the tunnel.
647
    ///
648
    /// If these restrictions are violated, the tunnel will be closed with an error.
649
    ///
650
    /// ## Precise definition of the lifetime of a conversation
651
    ///
652
    /// A conversation is in progress from entry to `start_conversation`,
653
    /// until entry to the body of the [`UserMsgHandler::handle_msg`](MsgHandler::handle_msg)
654
    /// call which returns [`ConversationFinished`](reactor::MetaCellDisposition::ConversationFinished).
655
    /// (*Entry* since `handle_msg` is synchronously embedded
656
    /// into the incoming message processing.)
657
    /// So you may start a new conversation as soon as you have the final response
658
    /// via your inter-task channel from (0) above.
659
    ///
660
    /// The lifetime relationship of the [`Conversation`],
661
    /// vs the handler returning `ConversationFinished`
662
    /// is not enforced by the type system.
663
    // Doing so without still leaving plenty of scope for runtime errors doesn't seem possible,
664
    // at least while allowing sending followup messages from outside the handler.
665
    #[cfg(feature = "send-control-msg")]
666
    pub async fn start_conversation(
667
        &self,
668
        msg: Option<tor_cell::relaycell::msg::AnyRelayMsg>,
669
        reply_handler: impl MsgHandler + Send + 'static,
670
        hop: TargetHop,
671
    ) -> Result<Conversation<'_>> {
672
        // We need to resolve the TargetHop into a precise HopLocation so our msg handler can match
673
        // the right Leg/Hop with inbound cell.
674
        let (sender, receiver) = oneshot::channel();
675
        self.circ
676
            .command
677
            .unbounded_send(CtrlCmd::ResolveTargetHop { hop, done: sender })
678
            .map_err(|_| Error::CircuitClosed)?;
679
        let hop_location = receiver.await.map_err(|_| Error::CircuitClosed)??;
680
        let handler = Box::new(UserMsgHandler::new(hop_location, reply_handler));
681
        let conversation = Conversation(self);
682
        conversation.send_internal(msg, Some(handler)).await?;
683
        Ok(conversation)
684
    }
685

            
686
    /// Shut down this tunnel, along with all streams that are using it. Happens asynchronously
687
    /// (i.e. the tunnel won't necessarily be done shutting down immediately after this function
688
    /// returns!).
689
    ///
690
    /// Note that other references to this tunnel may exist. If they do, they will stop working
691
    /// after you call this function.
692
    ///
693
    /// It's not necessary to call this method if you're just done with a tunnel: the tunnel should
694
    /// close on its own once nothing is using it any more.
695
    // TODO(conflux): This should use the ReactorHandle instead.
696
    pub fn terminate(&self) {
697
        let _ = self.circ.command.unbounded_send(CtrlCmd::Shutdown);
698
    }
699

            
700
    /// Helper: Send the resolve message, and read resolved message from
701
    /// resolve stream.
702
    async fn try_resolve(self: &Arc<Self>, msg: Resolve) -> Result<Resolved> {
703
        let components = self
704
            .begin_stream_impl(msg.into(), ResolveCmdChecker::new_any())
705
            .await?;
706

            
707
        let StreamComponents {
708
            stream_receiver,
709
            target: _,
710
            memquota,
711
            xon_xoff_reader_ctrl: _,
712
        } = components;
713

            
714
        let mut resolve_stream = ResolveStream::new(stream_receiver, memquota);
715
        resolve_stream.read_msg().await
716
    }
717

            
718
    // TODO(conflux)
719
}
720

            
721
// TODO(conflux): We will likely need to enforce some invariants here, for example that the `circ`
722
// has the expected (non-zero) number of hops.
723
impl TryFrom<ClientCirc> for ClientTunnel {
724
    type Error = Error;
725

            
726
189
    fn try_from(circ: ClientCirc) -> std::result::Result<Self, Self::Error> {
727
189
        Ok(Self { circ })
728
189
    }
729
}
730

            
731
/// Convert a [`ResolvedVal`] into a Result, based on whether or not
732
/// it represents an error.
733
fn resolvedval_to_result(val: ResolvedVal) -> Result<ResolvedVal> {
734
    match val {
735
        ResolvedVal::TransientError => Err(Error::ResolveError(ResolveError::Transient)),
736
        ResolvedVal::NontransientError => Err(Error::ResolveError(ResolveError::Nontransient)),
737
        ResolvedVal::Unrecognized(_, _) => Err(Error::ResolveError(ResolveError::Unrecognized)),
738
        _ => Ok(val),
739
    }
740
}
741

            
742
/// A precise position in a tunnel.
743
#[derive(Debug, Deftly, Copy, Clone, PartialEq, Eq)]
744
#[derive_deftly(HasMemoryCost)]
745
#[non_exhaustive]
746
pub enum HopLocation {
747
    /// A specific position in a tunnel.
748
    Hop((UniqId, HopNum)),
749
    /// The join point of a multi-path tunnel.
750
    JoinPoint,
751
}
752

            
753
/// A position in a tunnel.
754
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
755
#[non_exhaustive]
756
pub enum TargetHop {
757
    /// A specific position in a tunnel.
758
    Hop(HopLocation),
759
    /// The last hop of a tunnel.
760
    ///
761
    /// This should be used only when you don't care about what specific hop is used.
762
    /// Some tunnels may be extended or truncated,
763
    /// which means that the "last hop" may change at any time.
764
    LastHop,
765
}
766

            
767
impl From<(UniqId, HopNum)> for HopLocation {
768
86
    fn from(v: (UniqId, HopNum)) -> Self {
769
86
        HopLocation::Hop(v)
770
86
    }
771
}
772

            
773
impl From<(UniqId, HopNum)> for TargetHop {
774
8
    fn from(v: (UniqId, HopNum)) -> Self {
775
8
        TargetHop::Hop(v.into())
776
8
    }
777
}
778

            
779
impl HopLocation {
780
    /// Return the hop number if not a JointPoint.
781
    pub fn hop_num(&self) -> Option<HopNum> {
782
        match self {
783
            Self::Hop((_, hop_num)) => Some(*hop_num),
784
            Self::JoinPoint => None,
785
        }
786
    }
787
}
788

            
789
impl ClientTunnel {
790
    /// Close the pending stream that owns this StreamTarget, delivering the specified
791
    /// END message (if any)
792
    ///
793
    /// See [`StreamTarget::close_pending`].
794
    #[cfg(feature = "hs-service")]
795
6
    pub(crate) fn close_pending(
796
6
        &self,
797
6
        stream_id: StreamId,
798
6
        hop: Option<HopLocation>,
799
6
        message: crate::stream::CloseStreamBehavior,
800
6
    ) -> Result<oneshot::Receiver<Result<()>>> {
801
6
        let (tx, rx) = oneshot::channel();
802

            
803
6
        self.circ
804
6
            .control
805
6
            .unbounded_send(CtrlMsg::ClosePendingStream {
806
6
                stream_id,
807
6
                hop: hop.expect("missing stream hop for client tunnel"),
808
6
                message,
809
6
                done: tx,
810
6
            })
811
6
            .map_err(|_| Error::CircuitClosed)?;
812

            
813
6
        Ok(rx)
814
6
    }
815

            
816
    /// Request to send a SENDME cell for this stream.
817
    ///
818
    /// See [`StreamTarget::send_sendme`].
819
    pub(crate) fn send_sendme(&self, stream_id: StreamId, hop: Option<HopLocation>) -> Result<()> {
820
        self.circ
821
            .control
822
            .unbounded_send(CtrlMsg::FlowCtrlUpdate {
823
                msg: FlowCtrlMsg::Sendme,
824
                stream_id,
825
                hop: hop.expect("missing stream hop for client tunnel"),
826
            })
827
            .map_err(|_| Error::CircuitClosed)
828
    }
829

            
830
    /// Inform the circuit reactor that there has been a change in the drain rate for this stream.
831
    ///
832
    /// See [`StreamTarget::drain_rate_update`].
833
    pub(crate) fn drain_rate_update(
834
        &self,
835
        stream_id: StreamId,
836
        hop: Option<HopLocation>,
837
        rate: XonKBpsEwma,
838
    ) -> Result<()> {
839
        self.circ
840
            .control
841
            .unbounded_send(CtrlMsg::FlowCtrlUpdate {
842
                msg: FlowCtrlMsg::Xon(rate),
843
                stream_id,
844
                hop: hop.expect("missing stream hop for client tunnel"),
845
            })
846
            .map_err(|_| Error::CircuitClosed)
847
    }
848
}