direct_session.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. //! Direct connections session. Manages the creation of direct sessions.
  19. //! Used to create a direct session and to stop and start the session.
  20. //!
  21. //! A direct session is a type of outbound session in which a protocol can
  22. //! open a temporary channel (stopped after used) to a peer. Direct sessions
  23. //! do not loop continually, once stopped the session will not try to reopen
  24. //! a connection.
  25. //!
  26. //! If there is no slots in the outbound session, the direct session can
  27. //! optionally handle peer discovery.
  28. use std::{
  29. collections::HashMap,
  30. sync::{atomic::Ordering, Arc, Weak},
  31. time::Duration,
  32. };
  33. use async_trait::async_trait;
  34. use smol::lock::{Mutex as AsyncMutex, OnceCell};
  35. use tracing::{error, warn};
  36. use url::Url;
  37. use super::{
  38. super::{
  39. connector::Connector,
  40. dnet::{self, dnetev, DnetEvent},
  41. hosts::{HostColor, HostState},
  42. message::GetAddrsMessage,
  43. p2p::{P2p, P2pPtr},
  44. },
  45. Session, SessionBitFlag, SESSION_DIRECT,
  46. };
  47. use crate::{
  48. net::ChannelPtr,
  49. system::{
  50. msleep, sleep, timeout::timeout, CondVar, PublisherPtr, StoppableTask, StoppableTaskPtr,
  51. },
  52. util::logger::verbose,
  53. Error, Result,
  54. };
  55. pub type DirectSessionPtr = Arc<DirectSession>;
  56. /// Defines direct connections session.
  57. pub struct DirectSession {
  58. /// Weak pointer to parent p2p object
  59. pub(in crate::net) p2p: Weak<P2p>,
  60. /// Connector to create direct connections
  61. connector: OnceCell<Connector>,
  62. /// Tasks that are trying to create a direct channel (they retry until they succeed).
  63. /// A task is removed once the channel is successfully created.
  64. retries_tasks: Arc<AsyncMutex<HashMap<Url, Arc<StoppableTask>>>>,
  65. /// Peer discovery task
  66. peer_discovery: Arc<PeerDiscovery>,
  67. /// Channel ID -> usage count
  68. channels_usage: Arc<AsyncMutex<HashMap<u32, u32>>>,
  69. /// Pending channel creation tasks
  70. tasks: Arc<AsyncMutex<HashMap<Url, Weak<ChannelTask>>>>,
  71. }
  72. impl DirectSession {
  73. /// Create a new direct session.
  74. pub fn new(p2p: Weak<P2p>) -> DirectSessionPtr {
  75. Arc::new_cyclic(|session| Self {
  76. p2p,
  77. connector: OnceCell::new(),
  78. retries_tasks: Arc::new(AsyncMutex::new(HashMap::new())),
  79. peer_discovery: PeerDiscovery::new(session.clone()),
  80. channels_usage: Arc::new(AsyncMutex::new(HashMap::new())),
  81. tasks: Arc::new(AsyncMutex::new(HashMap::new())),
  82. })
  83. }
  84. /// Start the direct session.
  85. pub(crate) async fn start(self: Arc<Self>) {
  86. self.peer_discovery.clone().start().await;
  87. }
  88. /// Stops the direct session.
  89. pub async fn stop(&self) {
  90. self.peer_discovery.clone().stop().await;
  91. for (_, task) in self.retries_tasks.lock().await.iter() {
  92. task.stop().await;
  93. }
  94. }
  95. /// Notify the peer discovery task to start it.
  96. /// The direct session's peer discovery process will not start until this
  97. /// method is called.
  98. /// If there are outbound slots, peer discovery does not start even if this
  99. /// method is called, we let the outbound session take care of it.
  100. pub fn start_peer_discovery(&self) {
  101. self.peer_discovery.notify();
  102. }
  103. /// If there is an existing channel to the same address, this method will
  104. /// return it (even if the channel was not created by the direct session).
  105. /// Otherwise it will create a new channel to `addr` in the direct session.
  106. pub async fn get_channel(self: Arc<Self>, addr: &Url) -> Result<ChannelPtr> {
  107. // Check existing channels
  108. let channels = self.p2p().hosts().channels();
  109. if let Some(channel) =
  110. channels.iter().find(|&chan| chan.info.connect_addr == *addr).cloned()
  111. {
  112. let mut channels_usage = self.channels_usage.lock().await;
  113. if channel.is_stopped() {
  114. channel.clone().start(self.p2p().executor());
  115. }
  116. if channel.session_type_id() & SESSION_DIRECT != 0 {
  117. channels_usage.entry(channel.info.id).and_modify(|count| *count += 1).or_insert(1);
  118. }
  119. return Ok(channel);
  120. }
  121. let mut tasks = self.tasks.lock().await;
  122. // Check if task is already running for this addr
  123. if let Some(task) = tasks.get(addr) {
  124. if let Some(task) = task.upgrade() {
  125. drop(tasks);
  126. // Wait for the existing task to complete
  127. while task.output.lock().await.is_none() {
  128. msleep(100).await;
  129. }
  130. return task.output.lock().await.clone().unwrap();
  131. } else {
  132. drop(tasks);
  133. // Wait for the existing task to be fully removed
  134. loop {
  135. tasks = self.tasks.lock().await;
  136. if !tasks.contains_key(addr) {
  137. break
  138. }
  139. drop(tasks);
  140. msleep(100).await;
  141. }
  142. }
  143. }
  144. // If no task running, create one
  145. let task = Arc::new(ChannelTask {
  146. session: Arc::downgrade(&self.clone()),
  147. addr: addr.clone(),
  148. output: Arc::new(AsyncMutex::new(None)),
  149. });
  150. tasks.insert(addr.clone(), Arc::downgrade(&task));
  151. drop(tasks);
  152. // Spawn a new task to create the channel
  153. let ex = self.p2p().executor();
  154. let addr_ = addr.clone();
  155. let self_ = self.clone();
  156. let task_ = task.clone();
  157. ex.spawn(async move {
  158. let res = self_.clone().new_channel(addr_.clone()).await;
  159. let mut output = task_.output.lock().await;
  160. *output = Some(res);
  161. })
  162. .detach();
  163. // Wait for completion
  164. while task.output.lock().await.is_none() {
  165. msleep(100).await;
  166. }
  167. let res = task.output.lock().await.as_ref().unwrap().clone();
  168. if let Ok(ref channel) = res {
  169. self.inc_channel_usage(channel, Arc::strong_count(&task).try_into().unwrap()).await;
  170. }
  171. res
  172. }
  173. /// Increment channel usage
  174. pub async fn inc_channel_usage(&self, channel: &ChannelPtr, n: u32) {
  175. if channel.session_type_id() & SESSION_DIRECT == 0 {
  176. // Do nothing if this is not a channel created by the direct session
  177. return
  178. }
  179. let mut channels_usage = self.channels_usage.lock().await;
  180. channels_usage.entry(channel.info.id).and_modify(|count| *count += n).or_insert(n);
  181. }
  182. /// Try to create a new channel until it succeeds, then notify `channel_pub`.
  183. /// If it fails to create a channel, a task will sleep
  184. /// `outbound_connect_timeout` seconds and try again.
  185. pub async fn get_channel_with_retries(
  186. self: Arc<Self>,
  187. addr: Url,
  188. channel_pub: PublisherPtr<ChannelPtr>,
  189. ) {
  190. let task = StoppableTask::new();
  191. let self_ = self.clone();
  192. let mut retries_tasks = self.retries_tasks.lock().await;
  193. retries_tasks.insert(addr.clone(), task.clone());
  194. drop(retries_tasks);
  195. task.clone().start(
  196. async move {
  197. loop {
  198. let res = self_.clone().get_channel(&addr).await;
  199. match res {
  200. Ok(channel) => {
  201. channel_pub.notify(channel).await;
  202. let mut retries_tasks = self_.retries_tasks.lock().await;
  203. retries_tasks.remove(&addr);
  204. break
  205. }
  206. Err(_) => {
  207. let outbound_connect_timeout = self_
  208. .p2p()
  209. .settings()
  210. .read_arc()
  211. .await
  212. .outbound_connect_timeout(addr.scheme());
  213. sleep(outbound_connect_timeout).await;
  214. }
  215. }
  216. }
  217. Ok(())
  218. },
  219. |res| async {
  220. match res {
  221. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  222. Err(e) => {
  223. error!(target: "net::direct_session::get_channel_with_retries", "{e}")
  224. }
  225. }
  226. },
  227. Error::DetachedTaskStopped,
  228. self.p2p().executor(),
  229. );
  230. }
  231. async fn new_channel(self: Arc<Self>, addr: Url) -> Result<ChannelPtr> {
  232. if !self.connector.is_initialized() {
  233. let _ = self
  234. .connector
  235. .set(Connector::new(self.p2p().settings(), Arc::downgrade(&self.clone()).clone()))
  236. .await;
  237. }
  238. verbose!(
  239. target: "net::direct_session",
  240. "[P2P] Connecting to direct outbound [{addr}]",
  241. );
  242. let settings = self.p2p().settings().read_arc().await;
  243. let seeds = settings.seeds.clone();
  244. let active_profiles = settings.active_profiles.clone();
  245. drop(settings);
  246. // Do not establish a connection to a host that is also configured as a seed.
  247. // This indicates a user misconfiguration.
  248. if seeds.contains(&addr) {
  249. error!(
  250. target: "net::direct_session",
  251. "[P2P] Suspending direct connection to seed [{}]", addr.clone(),
  252. );
  253. return Err(Error::ConnectFailed(format!("[{addr}]: Direct connection to seed")))
  254. }
  255. // Abort if we are trying to connect to our own external address.
  256. let hosts = self.p2p().hosts();
  257. let external_addrs = hosts.external_addrs().await;
  258. if external_addrs.contains(&addr) {
  259. warn!(
  260. target: "net::hosts::check_addrs",
  261. "[P2P] Suspending direct connection to external addr [{}]", addr.clone(),
  262. );
  263. return Err(Error::ConnectFailed(format!(
  264. "[{addr}]: Direct connection to external addr"
  265. )))
  266. }
  267. // Abort if we do not support this transport.
  268. if !active_profiles.contains(&addr.scheme().to_string()) {
  269. return Err(Error::UnsupportedTransport(addr.scheme().to_string()))
  270. }
  271. // Abort if this peer is IPv6 and we do not support it.
  272. if !hosts.ipv6_available.load(Ordering::SeqCst) && hosts.is_ipv6(&addr) {
  273. return Err(Error::ConnectFailed(format!("[{addr}]: IPv6 is unavailable")))
  274. }
  275. // Set the addr to HostState::Connect
  276. loop {
  277. if let Err(e) = hosts.try_register(addr.clone(), HostState::Connect) {
  278. // If `try_register` failed because the addr is being refined, try again in a bit.
  279. if let Error::HostStateBlocked(from, _) = &e {
  280. if from == "Refine" {
  281. // TODO: Add a setting or have a way to wait for the refinery to complete
  282. sleep(5).await;
  283. continue
  284. }
  285. }
  286. error!(target: "net::direct_session",
  287. "[P2P] Cannot connect to direct={addr}, err={e}");
  288. return Err(e)
  289. }
  290. break
  291. }
  292. dnetev!(self, DirectConnecting, {
  293. connect_addr: addr.clone(),
  294. });
  295. // Attempt channel creation
  296. match self.connector.get().unwrap().connect(&addr).await {
  297. Ok((_, channel)) => {
  298. verbose!(
  299. target: "net::direct_session",
  300. "[P2P] Direct outbound connected [{}]",
  301. channel.display_address()
  302. );
  303. dnetev!(self, DirectConnected, {
  304. connect_addr: channel.info.connect_addr.clone(),
  305. addr: channel.display_address().clone(),
  306. channel_id: channel.info.id
  307. });
  308. // Register the new channel
  309. match self.register_channel(channel.clone(), self.p2p().executor()).await {
  310. Ok(()) => Ok(channel),
  311. Err(e) => {
  312. warn!(
  313. target: "net::direct_session",
  314. "[P2P] Unable to connect to direct outbound [{}]: {e}",
  315. channel.display_address(),
  316. );
  317. dnetev!(self, DirectDisconnected, {
  318. connect_addr: channel.info.connect_addr.clone(),
  319. err: e.to_string()
  320. });
  321. // Free up this addr for future operations.
  322. if let Err(e) = self.p2p().hosts().unregister(channel.address()) {
  323. warn!(target: "net::direct_session", "[P2P] Error while unregistering addr={}, err={e}", channel.display_address());
  324. }
  325. Err(e)
  326. }
  327. }
  328. }
  329. Err(e) => {
  330. warn!(
  331. target: "net::direct_session",
  332. "[P2P] Unable to connect to direct outbound: {e}",
  333. );
  334. dnetev!(self, DirectDisconnected, {
  335. connect_addr: addr.clone(),
  336. err: e.to_string()
  337. });
  338. // Free up this addr for future operations.
  339. if let Err(e) = self.p2p().hosts().unregister(&addr) {
  340. warn!(target: "net::direct_session", "[P2P] Error while unregistering addr={addr}, err={e}");
  341. }
  342. Err(e)
  343. }
  344. }
  345. }
  346. /// Close a direct channel if it's not used by anything.
  347. /// `AsyncDrop` would be great here (<https://doc.rust-lang.org/std/future/trait.AsyncDrop.html>)
  348. /// but it's still in nightly. For now you must call this method manually
  349. /// once you are done with a direct channel.
  350. /// Returns `true` if the channel is stopped.
  351. pub async fn cleanup_channel(self: Arc<Self>, channel: ChannelPtr) -> bool {
  352. if channel.session_type_id() & SESSION_DIRECT == 0 {
  353. // Do nothing if this is not a channel created by the direct session
  354. return false
  355. }
  356. let mut channels_usage = self.channels_usage.lock().await;
  357. let usage_count = channels_usage.get_mut(&channel.info.id);
  358. if usage_count.is_none() {
  359. let _ = self.p2p().hosts().unregister(channel.address());
  360. channel.stop().await;
  361. return true
  362. }
  363. let usage_count = usage_count.unwrap();
  364. if *usage_count > 0 {
  365. *usage_count -= 1;
  366. }
  367. if *usage_count == 0 {
  368. channels_usage.remove(&channel.info.id);
  369. let _ = self.p2p().hosts().unregister(channel.address());
  370. channel.stop().await;
  371. return true
  372. }
  373. false
  374. }
  375. }
  376. #[async_trait]
  377. impl Session for DirectSession {
  378. fn p2p(&self) -> P2pPtr {
  379. self.p2p.upgrade().unwrap()
  380. }
  381. fn type_id(&self) -> SessionBitFlag {
  382. SESSION_DIRECT
  383. }
  384. async fn reload(self: Arc<Self>) {}
  385. }
  386. struct ChannelTask {
  387. session: Weak<DirectSession>,
  388. addr: Url,
  389. output: Arc<AsyncMutex<Option<Result<ChannelPtr>>>>,
  390. }
  391. impl Drop for ChannelTask {
  392. fn drop(&mut self) {
  393. let session = self.session.upgrade().unwrap();
  394. let addr = self.addr.clone();
  395. session
  396. .p2p()
  397. .executor()
  398. .spawn(async move {
  399. let mut tasks = session.tasks.lock().await;
  400. tasks.remove(&addr);
  401. })
  402. .detach();
  403. }
  404. }
  405. /// PeerDiscovery process for that sends `GetAddrs` messages to a random
  406. /// whitelist or greylist host (creating a channel in the direct session).
  407. /// If it's unsuccessful after two attempts, connect to our seed nodes and
  408. /// perform `SeedSyncSession`.
  409. struct PeerDiscovery {
  410. process: StoppableTaskPtr,
  411. init: CondVar,
  412. session: Weak<DirectSession>,
  413. }
  414. impl PeerDiscovery {
  415. fn new(session: Weak<DirectSession>) -> Arc<Self> {
  416. Arc::new(Self { process: StoppableTask::new(), init: CondVar::new(), session })
  417. }
  418. }
  419. impl PeerDiscovery {
  420. async fn start(self: Arc<Self>) {
  421. let ex = self.p2p().executor();
  422. self.process.clone().start(
  423. async move {
  424. self.run().await;
  425. Ok(())
  426. },
  427. // Ignore stop handler
  428. |_| async {},
  429. Error::NetworkServiceStopped,
  430. ex,
  431. );
  432. }
  433. async fn stop(self: Arc<Self>) {
  434. self.process.stop().await;
  435. }
  436. /// Peer discovery's main process. For the first two attempts, this will
  437. /// broadcast a `GetAddrs` message to request more peers. If we are not
  438. /// connected to any peer, we try to create a channel in the direct session
  439. /// to a random whitelist or greylist host.
  440. /// Other parts of the P2P stack will then handle the incoming addresses
  441. /// and place them in the hosts list.
  442. ///
  443. /// On the third attempt, and if we still haven't made any connections,
  444. /// this function will then call `p2p.seed()` which triggers a
  445. /// `SeedSyncSession` that will connect to configured seeds and request
  446. /// peers from them.
  447. ///
  448. /// This function will also sleep `outbound_peer_discovery_attempt_time`
  449. /// seconds after broadcasting in order to let the P2P stack receive and
  450. /// work through the addresses it is expecting.
  451. ///
  452. /// Peer discovery will only start once `notify()` is called.
  453. async fn run(self: Arc<Self>) {
  454. // DirectSession can handle peer discovery only if there is no outbound
  455. // slot. Otherwise we let the outbound session take care of it.
  456. let settings = self.p2p().settings().read_arc().await;
  457. if settings.outbound_connections > 0 {
  458. return
  459. }
  460. // Wait for the peer discovery to be notified
  461. self.init.wait().await;
  462. let mut current_attempt = 0;
  463. loop {
  464. dnetev!(self, DirectPeerDiscovery, {
  465. attempt: current_attempt,
  466. state: "wait",
  467. });
  468. // Read the current P2P settings
  469. let settings = self.p2p().settings().read_arc().await;
  470. let outbound_peer_discovery_cooloff_time =
  471. settings.outbound_peer_discovery_cooloff_time;
  472. let outbound_peer_discovery_attempt_time =
  473. settings.outbound_peer_discovery_attempt_time;
  474. let getaddrs_max = settings.getaddrs_max;
  475. let active_profiles = settings.active_profiles.clone();
  476. let seeds = settings.seeds.clone();
  477. drop(settings);
  478. current_attempt += 1;
  479. if current_attempt >= 4 {
  480. verbose!(
  481. target: "net::direct_session::peer_discovery",
  482. "[P2P] [PEER DISCOVERY] Sleeping and trying again. Attempt {current_attempt}"
  483. );
  484. dnetev!(self, DirectPeerDiscovery, {
  485. attempt: current_attempt,
  486. state: "sleep",
  487. });
  488. sleep(outbound_peer_discovery_cooloff_time).await;
  489. current_attempt = 1;
  490. }
  491. // If we are not connected to any peer, try to create a channel
  492. // (using the direct session) to a random host from the goldlist,
  493. // whitelist, or greylist.
  494. let mut channel = None;
  495. if !self.p2p().is_connected() {
  496. dnetev!(self, DirectPeerDiscovery, {
  497. attempt: current_attempt,
  498. state: "newchan",
  499. });
  500. for color in [HostColor::Gold, HostColor::White, HostColor::Grey].iter() {
  501. if let Some((url, _last_seen)) = self
  502. .p2p()
  503. .hosts()
  504. .container
  505. .fetch_random_with_schemes(*color, &active_profiles)
  506. {
  507. channel = self.p2p().session_direct().get_channel(&url).await.ok();
  508. break;
  509. }
  510. }
  511. }
  512. // First 2 times try sending GetAddr to the network.
  513. // 3rd time do a seed sync (providing we have seeds configured).
  514. if self.p2p().is_connected() && current_attempt <= 2 {
  515. // Broadcast the GetAddrs message to all active peers.
  516. // If we have no active peers, we will perform a SeedSyncSession instead.
  517. verbose!(
  518. target: "net::direct_session::peer_discovery",
  519. "[P2P] [PEER DISCOVERY] Asking peers for new peers to connect to...");
  520. dnetev!(self, DirectPeerDiscovery, {
  521. attempt: current_attempt,
  522. state: "getaddr",
  523. });
  524. let get_addrs =
  525. GetAddrsMessage { max: getaddrs_max.unwrap_or(1), transports: active_profiles };
  526. self.p2p().broadcast(&get_addrs).await;
  527. // Wait for a hosts store update event
  528. let store_sub = self.p2p().hosts().subscribe_store().await;
  529. let result = timeout(
  530. Duration::from_secs(outbound_peer_discovery_attempt_time),
  531. store_sub.receive(),
  532. )
  533. .await;
  534. match result {
  535. Ok(addrs_len) => {
  536. verbose!(
  537. target: "net::direct_session::peer_discovery",
  538. "[P2P] [PEER DISCOVERY] Discovered {addrs_len} peers"
  539. );
  540. // Found some addrs, reset `current_attempt`
  541. if addrs_len > 0 {
  542. current_attempt = 0;
  543. }
  544. }
  545. Err(_) => {
  546. verbose!(
  547. target: "net::direct_session::peer_discovery",
  548. "[P2P] [PEER DISCOVERY] Waiting for addrs timed out."
  549. );
  550. // Just do seed next time
  551. current_attempt = 3;
  552. }
  553. }
  554. // NOTE: not every call to subscribe() in net/ has a
  555. // corresponding unsubscribe(). To do this we need async
  556. // Drop. For now it's sufficient for publishers to be
  557. // de-allocated when the Session completes.
  558. store_sub.unsubscribe().await;
  559. } else if !seeds.is_empty() {
  560. verbose!(
  561. target: "net::direct_session::peer_discovery",
  562. "[P2P] [PEER DISCOVERY] Asking seeds for new peers to connect to...");
  563. dnetev!(self, DirectPeerDiscovery, {
  564. attempt: current_attempt,
  565. state: "seed",
  566. });
  567. self.p2p().seed().await;
  568. }
  569. // Stop the channel we created for peer discovery
  570. if let Some(ch) = channel {
  571. self.p2p().session_direct().cleanup_channel(ch).await;
  572. }
  573. // Give some time for new connections to be established
  574. sleep(outbound_peer_discovery_attempt_time).await;
  575. }
  576. }
  577. /// Init peer discovery by sending a notification to `init`.
  578. /// Uses the underlying `CondVar` method `notify()`.
  579. pub fn notify(&self) {
  580. self.init.notify()
  581. }
  582. fn session(&self) -> DirectSessionPtr {
  583. self.session.upgrade().unwrap()
  584. }
  585. fn p2p(&self) -> P2pPtr {
  586. self.session().p2p()
  587. }
  588. }