1use cfg_if::cfg_if;
7
8use tor_cell::relaycell::hs::intro_payload::IntroduceHandshakePayload;
9use tor_netdoc::doc::hsdesc::HsDesc;
10use tor_protover::Protocols;
11
12cfg_if! {
13 if #[cfg(feature = "negotiate-extensions")] {
14 use tor_protover::{NamedSubver, NumberedSubver, named::*};
15
16 static REQUESTABLE_LIST: &[NamedSubver] = &[RELAY_CRYPT_CGO];
21 }
22}
23
24#[derive(Clone, Debug)]
26pub(crate) struct PeerCaps {
27 #[cfg(feature = "negotiate-extensions")]
31 shared_protos: Protocols,
32
33 #[cfg(feature = "negotiate-extensions")]
36 request_protos: Protocols,
37
38 #[cfg(feature = "negotiate-extensions")]
42 sendme_inc: Option<u8>,
43}
44
45#[cfg(feature = "negotiate-extensions")]
46impl PeerCaps {
47 pub(crate) fn new(desc: &HsDesc) -> Self {
49 let supported = tor_proto::supported_client_protocols();
50
51 let (fc_protos, sendme_inc) = if let Some((fcp, inc)) = desc.flow_control()
52 && fcp.supports_named_subver(FLOWCTRL_CC)
53 && supported.supports_named_subver(FLOWCTRL_CC)
54 {
55 ([FLOWCTRL_CC].into_iter().collect(), Some(inc.into()))
56 } else {
57 (Protocols::new(), None)
58 };
59
60 let mut subproto_request = Vec::new();
61 let mutual_protos = desc.declared_capabilities().intersection(&supported);
62
63 if mutual_protos.supports_named_subver(RELAY_CRYPT_CGO)
65 && mutual_protos.supports_named_subver(RELAY_NEGOTIATE_SUBPROTO)
66 && fc_protos.supports_named_subver(FLOWCTRL_CC)
67 {
68 subproto_request.push(RELAY_CRYPT_CGO);
69 }
70
71 let request_protos: Protocols = subproto_request.into_iter().collect();
72
73 let shared_protos = request_protos.union(&fc_protos);
74
75 PeerCaps {
76 shared_protos,
77 request_protos,
78 sendme_inc,
79 }
80 }
81
82 pub(crate) fn add_extensions(&self, intro: &mut IntroduceHandshakePayload) {
84 use tor_cell::relaycell::extend::{CcRequest, SubprotocolRequest};
85
86 if self.sendme_inc.is_some() {
87 intro.add_extension(CcRequest::default().into());
88 }
89 if !self.request_protos.is_empty() {
90 let ext: SubprotocolRequest = REQUESTABLE_LIST
91 .iter()
92 .filter(|p| self.request_protos.supports_named_subver(**p))
93 .map(|p| NumberedSubver::from(*p))
94 .collect();
95 intro.add_extension(ext.into());
96 }
97 }
98
99 pub(crate) fn shared_protos(&self) -> Protocols {
101 self.shared_protos.clone()
102 }
103
104 pub(crate) fn cc_sendme_inc(&self) -> Option<u8> {
108 self.sendme_inc
109 }
110}
111
112#[cfg(not(feature = "negotiate-extensions"))]
113impl PeerCaps {
114 pub(crate) fn new(_desc: &HsDesc) -> Self {
116 Self {}
117 }
118
119 pub(crate) fn add_extensions(&self, _intro: &mut IntroduceHandshakePayload) {}
121
122 pub(crate) fn shared_protos(&self) -> Protocols {
124 Protocols::new()
127 }
128
129 pub(crate) fn cc_sendme_inc(&self) -> Option<u8> {
133 None
134 }
135}