outbound_session.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 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. //! Outbound connections session. Manages the creation of outbound sessions.
  19. //! Used to create an outbound session and to stop and start the session.
  20. //!
  21. //! Class consists of a weak pointer to the p2p interface and a vector of
  22. //! outbound connection slots. Using a weak pointer to p2p allows us to
  23. //! avoid circular dependencies. The vector of slots is wrapped in a mutex
  24. //! lock. This is switched on every time we instantiate a connection slot
  25. //! and insures that no other part of the program uses the slots at the
  26. //! same time.
  27. use std::{
  28. sync::{
  29. atomic::{AtomicU32, Ordering},
  30. Arc, Weak,
  31. },
  32. time::{Duration, Instant, SystemTime},
  33. };
  34. use async_trait::async_trait;
  35. use log::{debug, error, info, warn};
  36. use rand::{
  37. Rng,
  38. };
  39. use smol::lock::Mutex;
  40. use url::Url;
  41. use super::{
  42. super::{
  43. channel::ChannelPtr,
  44. connector::Connector,
  45. dnet::{self, dnetev, DnetEvent},
  46. message::GetAddrsMessage,
  47. p2p::{P2p, P2pPtr},
  48. protocol::ProtocolVersion,
  49. },
  50. Session, SessionBitFlag, SESSION_OUTBOUND,
  51. };
  52. use crate::{
  53. system::{
  54. sleep, timeout::timeout, CondVar, LazyWeak, StoppableTask, StoppableTaskPtr, Subscriber,
  55. SubscriberPtr,
  56. },
  57. Error, Result,
  58. };
  59. pub type OutboundSessionPtr = Arc<OutboundSession>;
  60. /// Defines outbound connections session.
  61. pub struct OutboundSession {
  62. /// Weak pointer to parent p2p object
  63. pub(in crate::net) p2p: LazyWeak<P2p>,
  64. /// Subscriber used to signal channels processing
  65. channel_subscriber: SubscriberPtr<Result<ChannelPtr>>,
  66. /// Outbound connection slots
  67. slots: Mutex<Vec<Arc<Slot>>>,
  68. /// Peer discovery task
  69. peer_discovery: Arc<PeerDiscovery>,
  70. }
  71. impl OutboundSession {
  72. /// Create a new outbound session.
  73. pub(crate) fn new() -> OutboundSessionPtr {
  74. let self_ = Arc::new(Self {
  75. p2p: LazyWeak::new(),
  76. channel_subscriber: Subscriber::new(),
  77. slots: Mutex::new(Vec::new()),
  78. peer_discovery: PeerDiscovery::new(),
  79. });
  80. self_.peer_discovery.session.init(self_.clone());
  81. self_
  82. }
  83. /// Start the outbound session. Runs the channel connect loop.
  84. pub(crate) async fn start(self: Arc<Self>) {
  85. let n_slots = self.p2p().settings().outbound_connections;
  86. info!(target: "net::outbound_session", "[P2P] Starting {} outbound connection slots.", n_slots);
  87. // Activate mutex lock on connection slots.
  88. let mut slots = self.slots.lock().await;
  89. let self_ = Arc::downgrade(&self);
  90. for i in 0..n_slots as u32 {
  91. let slot = Slot::new(self_.clone(), i);
  92. slot.clone().start().await;
  93. slots.push(slot);
  94. }
  95. self.peer_discovery.clone().start().await;
  96. }
  97. /// Stops the outbound session.
  98. pub(crate) async fn stop(&self) {
  99. let slots = &*self.slots.lock().await;
  100. for slot in slots {
  101. slot.clone().stop().await;
  102. }
  103. self.peer_discovery.clone().stop().await;
  104. }
  105. pub async fn slot_info(&self) -> Vec<u32> {
  106. let mut info = Vec::new();
  107. let slots = &*self.slots.lock().await;
  108. for slot in slots {
  109. info.push(slot.channel_id.load(Ordering::Relaxed));
  110. }
  111. info
  112. }
  113. fn wakeup_peer_discovery(&self) {
  114. self.peer_discovery.notify()
  115. }
  116. async fn wakeup_slots(&self) {
  117. let slots = &*self.slots.lock().await;
  118. for slot in slots {
  119. slot.notify();
  120. }
  121. }
  122. }
  123. #[async_trait]
  124. impl Session for OutboundSession {
  125. fn p2p(&self) -> P2pPtr {
  126. self.p2p.upgrade()
  127. }
  128. fn type_id(&self) -> SessionBitFlag {
  129. SESSION_OUTBOUND
  130. }
  131. }
  132. pub struct Slot {
  133. slot: u32,
  134. process: StoppableTaskPtr,
  135. wakeup_self: CondVar,
  136. session: Weak<OutboundSession>,
  137. // For debugging
  138. channel_id: AtomicU32,
  139. }
  140. impl Slot {
  141. fn new(session: Weak<OutboundSession>, slot: u32) -> Arc<Self> {
  142. Arc::new(Self {
  143. slot,
  144. process: StoppableTask::new(),
  145. wakeup_self: CondVar::new(),
  146. session,
  147. channel_id: AtomicU32::new(0),
  148. })
  149. }
  150. async fn start(self: Arc<Self>) {
  151. // TODO: way too many clones, look into making this implicit. See implicit-clone crate
  152. let ex = self.p2p().executor();
  153. self.process.clone().start(
  154. async move {
  155. self.run().await;
  156. unreachable!();
  157. },
  158. // Ignore stop handler
  159. |_| async {},
  160. Error::NetworkServiceStopped,
  161. ex,
  162. );
  163. }
  164. async fn stop(self: Arc<Self>) {
  165. self.process.stop().await
  166. }
  167. // TODO: clean documentation
  168. // Looks up whitelisted addresses. Tries to connect to them.
  169. // On success, updates the whitelist last_seen field.
  170. async fn run(self: Arc<Self>) {
  171. // This is the main outbound connection loop where we try to establish
  172. // a connection in the slot. The `try_connect` function will block in
  173. // case the connection was sucessfully established. If it fails, then
  174. // we will wait for a defined number of seconds and try to fill the
  175. // slot again. This function should never exit during the lifetime of
  176. // the P2P network, as it is supposed to represent an outbound slot we
  177. // want to fill.
  178. // The actual connection logic and peer selection is in `try_connect`.
  179. // If the connection is successful, `try_connect` will wait for a stop
  180. // signal and then exit. Once it exits, we'll run `try_connect` again
  181. // and attempt to fill the slot with another peer.
  182. let hosts = self.p2p().hosts();
  183. loop {
  184. // Activate the slot
  185. debug!(
  186. target: "net::outbound_session::try_connect()",
  187. "[P2P] Finding a host to connect to for outbound slot #{}",
  188. self.slot,
  189. );
  190. // Retrieve outbound transports
  191. let transports = &self.p2p().settings().allowed_transports;
  192. // Find a whitelisted address to connect to. We also do peer discovery here if needed.
  193. let (addr, _last_seen) = if let Some(addr) =
  194. hosts.whitelist_fetch_address_with_lock(self.p2p(), transports).await
  195. {
  196. addr
  197. } else {
  198. dnetev!(self, OutboundSlotSleeping, {
  199. slot: self.slot,
  200. });
  201. self.wakeup_self.reset();
  202. // Peer discovery
  203. self.session().wakeup_peer_discovery();
  204. // Wait to be woken up by peer discovery
  205. self.wakeup_self.wait().await;
  206. continue
  207. };
  208. info!(
  209. target: "net::outbound_session::try_connect()",
  210. "[P2P] Connecting outbound slot #{} [{}]",
  211. self.slot, addr,
  212. );
  213. dnetev!(self, OutboundSlotConnecting, {
  214. slot: self.slot,
  215. addr: addr.clone(),
  216. });
  217. let (addr_final, channel) =
  218. match self.try_connect(addr.clone()).await {
  219. Ok(connect_info) => connect_info,
  220. Err(err) => {
  221. error!(
  222. target: "net::outbound_session",
  223. "[P2P] Outbound slot #{} connection failed: {}",
  224. self.slot, err,
  225. );
  226. dnetev!(self, OutboundSlotDisconnected, {
  227. slot: self.slot,
  228. err: err.to_string()
  229. });
  230. self.channel_id.store(0, Ordering::Relaxed);
  231. continue
  232. }
  233. };
  234. info!(
  235. target: "net::outbound_session::try_connect()",
  236. "[P2P] Outbound slot #{} connected [{}]",
  237. self.slot, addr_final
  238. );
  239. // Update the last_seen field for this whitelisted peer.
  240. // TODO: This peer should also be flagged as an "anchor" because we have been
  241. // able to establish a connection to it to it.
  242. let last_seen =
  243. SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
  244. hosts.whitelist_update(&addr_final, last_seen).await;
  245. dnetev!(self, OutboundSlotConnected, {
  246. slot: self.slot,
  247. addr: addr_final.clone(),
  248. channel_id: channel.info.id
  249. });
  250. let stop_sub = channel.subscribe_stop().await.expect("Channel should not be stopped");
  251. // Setup new channel
  252. if let Err(err) = self.setup_channel(addr, channel.clone()).await {
  253. info!(
  254. target: "net::outbound_session",
  255. "[P2P] Outbound slot #{} disconnected: {}",
  256. self.slot, err
  257. );
  258. dnetev!(self, OutboundSlotDisconnected, {
  259. slot: self.slot,
  260. err: err.to_string()
  261. });
  262. self.channel_id.store(0, Ordering::Relaxed);
  263. continue
  264. }
  265. self.channel_id.store(channel.info.id, Ordering::Relaxed);
  266. // Wait for channel to close
  267. stop_sub.receive().await;
  268. self.channel_id.store(0, Ordering::Relaxed);
  269. }
  270. }
  271. /// Start making an outbound connection, using provided [`Connector`].
  272. /// Tries to find a valid address to connect to, otherwise does peer
  273. /// discovery. The peer discovery loops until some peer we can connect
  274. /// to is found. Once connected, registers the channel, removes it from
  275. /// the list of pending channels, and starts sending messages across the
  276. /// channel. In case of any failures, a network error is returned and the
  277. /// main connect loop (parent of this function) will iterate again.
  278. async fn try_connect(&self, addr: Url) -> Result<(Url, ChannelPtr)> {
  279. let parent = Arc::downgrade(&self.session());
  280. let connector = Connector::new(self.p2p().settings(), parent);
  281. match connector.connect(&addr).await {
  282. Ok((addr_final, channel)) => Ok((addr_final, channel)),
  283. Err(e) => {
  284. error!(
  285. target: "net::outbound_session::try_connect()",
  286. "[P2P] Unable to connect outbound slot #{} [{}]: {}",
  287. self.slot, addr, e
  288. );
  289. // At this point we failed to connect.
  290. // Remove this item from the whitelist and add it to the greylist.
  291. self.p2p().hosts().whitelist_downgrade(&addr).await;
  292. // Remove connection from pending
  293. self.p2p().remove_pending(&addr).await;
  294. // Notify that channel processing failed
  295. self.session().channel_subscriber.notify(Err(Error::ConnectFailed)).await;
  296. Err(Error::ConnectFailed)
  297. }
  298. }
  299. }
  300. async fn setup_channel(&self, addr: Url, channel: ChannelPtr) -> Result<()> {
  301. // Register the new channel
  302. self.session().register_channel(channel.clone(), self.p2p().executor()).await?;
  303. // Channel is now connected but not yet setup
  304. // Remove pending lock since register_channel will add the channel to p2p
  305. self.p2p().remove_pending(&addr).await;
  306. // Notify that channel processing has been finished
  307. self.session().channel_subscriber.notify(Ok(channel)).await;
  308. Ok(())
  309. }
  310. ///// TODO: this method should go in hosts
  311. fn notify(&self) {
  312. self.wakeup_self.notify()
  313. }
  314. fn session(&self) -> OutboundSessionPtr {
  315. self.session.upgrade().unwrap()
  316. }
  317. fn p2p(&self) -> P2pPtr {
  318. self.session().p2p()
  319. }
  320. }
  321. struct PeerDiscovery {
  322. process: StoppableTaskPtr,
  323. wakeup_self: CondVar,
  324. session: LazyWeak<OutboundSession>,
  325. }
  326. impl PeerDiscovery {
  327. fn new() -> Arc<Self> {
  328. Arc::new(Self {
  329. process: StoppableTask::new(),
  330. wakeup_self: CondVar::new(),
  331. session: LazyWeak::new(),
  332. })
  333. }
  334. async fn start(self: Arc<Self>) {
  335. let ex = self.p2p().executor();
  336. self.process.clone().start(
  337. async move {
  338. self.run().await;
  339. unreachable!();
  340. },
  341. // Ignore stop handler
  342. |_| async {},
  343. Error::NetworkServiceStopped,
  344. ex,
  345. );
  346. }
  347. async fn stop(self: Arc<Self>) {
  348. self.process.stop().await
  349. }
  350. /// Activate peer discovery if not active already. This will loop through all
  351. /// connected P2P channels and send out a `GetAddrs` message to request more
  352. /// peers. Other parts of the P2P stack will then handle the incoming addresses
  353. /// and place them in the hosts list.
  354. /// This function will also sleep `Settings::outbound_connect_timeout` seconds
  355. /// after broadcasting in order to let the P2P stack receive and work through
  356. /// the addresses it is expecting.
  357. async fn run(self: Arc<Self>) {
  358. let mut current_attempt = 0;
  359. loop {
  360. dnetev!(self, OutboundPeerDiscovery, {
  361. attempt: current_attempt,
  362. state: "wait",
  363. });
  364. // wait to be woken up by notify()
  365. let sleep_was_instant = self.wait().await;
  366. let p2p = self.p2p();
  367. if sleep_was_instant {
  368. // Try again
  369. current_attempt += 1;
  370. } else {
  371. // reset back to start
  372. current_attempt = 1;
  373. }
  374. if current_attempt >= 4 {
  375. info!(
  376. target: "net::outbound_session::peer_discovery()",
  377. "[P2P] Sleeping and trying again..."
  378. );
  379. dnetev!(self, OutboundPeerDiscovery, {
  380. attempt: current_attempt,
  381. state: "sleep",
  382. });
  383. sleep(p2p.settings().outbound_peer_discovery_cooloff_time).await;
  384. current_attempt = 1;
  385. }
  386. // First 2 times try sending GetAddr to the network.
  387. // 3rd time do a seed sync.
  388. if p2p.is_connected().await && current_attempt <= 2 {
  389. // Broadcast the GetAddrs message to all active channels.
  390. // If we have no active channels, we will perform a SeedSyncSession instead.
  391. info!(
  392. target: "net::outbound_session::peer_discovery()",
  393. "[P2P] Requesting addrs from active channels. Attempt: {}",
  394. current_attempt
  395. );
  396. dnetev!(self, OutboundPeerDiscovery, {
  397. attempt: current_attempt,
  398. state: "getaddr",
  399. });
  400. let get_addrs = GetAddrsMessage {
  401. max: p2p.settings().outbound_connections as u32,
  402. transports: p2p.settings().allowed_transports.clone(),
  403. };
  404. p2p.broadcast(&get_addrs).await;
  405. // Wait for a hosts store update event
  406. let store_sub = self.p2p().hosts().subscribe_store().await.unwrap();
  407. let result = timeout(
  408. Duration::from_secs(p2p.settings().outbound_peer_discovery_attempt_time),
  409. store_sub.receive(),
  410. )
  411. .await;
  412. match result {
  413. Ok(addrs_len) => {
  414. info!(
  415. target: "net::outbound_session::peer_discovery()",
  416. "[P2P] Discovered {} addrs", addrs_len
  417. );
  418. }
  419. Err(_) => {
  420. warn!(
  421. target: "net::outbound_session::peer_discovery()",
  422. "[P2P] Peer discovery waiting for addrs timed out."
  423. );
  424. // TODO: Just do seed next time
  425. }
  426. }
  427. // TODO: check every subscribe() call has a corresponding unsubscribe()
  428. store_sub.unsubscribe().await;
  429. } else {
  430. info!(
  431. target: "net::outbound_session::peer_discovery()",
  432. "[P2P] Seeding hosts. Attempt: {}",
  433. current_attempt
  434. );
  435. dnetev!(self, OutboundPeerDiscovery, {
  436. attempt: current_attempt,
  437. state: "seed",
  438. });
  439. match p2p.clone().seed().await {
  440. Ok(()) => {
  441. info!(
  442. target: "net::outbound_session::peer_discovery()",
  443. "[P2P] Seeding hosts successful."
  444. );
  445. }
  446. Err(err) => {
  447. error!(
  448. target: "net::outbound_session::peer_discovery()",
  449. "[P2P] Network reseed failed: {}", err,
  450. );
  451. }
  452. }
  453. }
  454. self.wakeup_self.reset();
  455. self.session().wakeup_slots().await;
  456. // Give some time for new connections to be established
  457. sleep(p2p.settings().outbound_peer_discovery_attempt_time).await;
  458. }
  459. }
  460. async fn wait(&self) -> bool {
  461. let wakeup_start = Instant::now();
  462. self.wakeup_self.wait().await;
  463. let wakeup_end = Instant::now();
  464. let epsilon = Duration::from_millis(200);
  465. wakeup_end - wakeup_start <= epsilon
  466. }
  467. fn notify(&self) {
  468. self.wakeup_self.notify()
  469. }
  470. fn session(&self) -> OutboundSessionPtr {
  471. self.session.upgrade()
  472. }
  473. fn p2p(&self) -> P2pPtr {
  474. self.session().p2p()
  475. }
  476. }
  477. //// Probe random peers on the greylist. If a peer is responsive, update the last_seen field and
  478. //// add it to the whitelist. If a node does not respond, remove it from the greylist.
  479. //// Called periodically.
  480. // NOTE: in monero this is called "greylist housekeeping" but that's a bit verbose.
  481. struct GreylistRefinery {
  482. process: StoppableTaskPtr,
  483. //wakeup_self: CondVar,
  484. session: LazyWeak<OutboundSession>,
  485. }
  486. impl GreylistRefinery {
  487. fn new() -> Arc<Self> {
  488. Arc::new(Self {
  489. process: StoppableTask::new(),
  490. //wakeup_self: CondVar::new(),
  491. session: LazyWeak::new(),
  492. })
  493. }
  494. //async fn start(self: Arc<Self>) {
  495. // let ex = self.p2p().executor();
  496. // self.process.clone().start(
  497. // async move {
  498. // self.run().await;
  499. // unreachable!();
  500. // },
  501. // // Ignore stop handler
  502. // |_| async {},
  503. // Error::NetworkServiceStopped,
  504. // ex,
  505. // );
  506. //}
  507. async fn stop(self: Arc<Self>) {
  508. self.process.stop().await
  509. }
  510. //// Randomly select a peer on the greylist and probe it.
  511. //// TODO: This frequency of this call can be set in net::Settings.
  512. async fn run(self: Arc<Self>) {
  513. loop {
  514. let p2p = self.p2p();
  515. let hosts = p2p.hosts();
  516. let session = self.session();
  517. let greylist = hosts.greylist.read().await;
  518. //// Randomly select an entry from the greylist.
  519. let position = rand::thread_rng().gen_range(0..greylist.len());
  520. let entry = &greylist[position];
  521. let url = &entry.0;
  522. let parent = Arc::downgrade(&self.session());
  523. let mut greylist = hosts.greylist.write().await;
  524. let mut whitelist = hosts.whitelist.write().await;
  525. let connector = Connector::new(p2p.settings(), parent);
  526. debug!(target: "net::greylist_refinery::run()", "Connecting to {}", url);
  527. match connector.connect(url).await {
  528. Ok((_url, channel)) => {
  529. debug!(target: "net::greylist_refinery::run()", "Connected successfully!");
  530. let proto_ver = ProtocolVersion::new(channel.clone(), p2p.settings()).await;
  531. let handshake_task = session.perform_handshake_protocols(
  532. proto_ver,
  533. channel.clone(),
  534. p2p.executor(),
  535. );
  536. channel.clone().start(p2p.executor());
  537. match handshake_task.await {
  538. Ok(()) => {
  539. debug!(target: "net::greylist_refinery::run()", "Handshake success! Stopping channel.");
  540. channel.stop().await;
  541. // Peer is responsive. Update last_seen and add it to the whitelist.
  542. let last_seen = SystemTime::now()
  543. .duration_since(SystemTime::UNIX_EPOCH)
  544. .unwrap()
  545. .as_secs();
  546. // Remove oldest element if the whitelist reaches max size.
  547. if whitelist.len() == 1000 {
  548. // Last element in vector should have the oldest timestamp.
  549. // This should never crash as only returns None when whitelist len() == 0.
  550. let entry = whitelist.pop().unwrap();
  551. debug!(target: "net::greylist_refinery::run()", "Whitelist reached max size. Removed host {}", entry.0);
  552. }
  553. // Append to the whitelist.
  554. debug!(target: "net::greylist_refinery::run()", "Adding peer {} to whitelist", url);
  555. whitelist.push((url.clone(), last_seen));
  556. // Sort whitelist by last_seen.
  557. whitelist.sort_unstable_by_key(|entry| entry.1);
  558. // Remove whitelisted peer from the greylist.
  559. debug!(target: "net::greylist_refinery::run()", "Removing whitelisted peer {} from greylist", url);
  560. greylist.remove(position);
  561. }
  562. Err(e) => {
  563. debug!(target: "net::hosts::probe_node()", "Handshake failure! {}", e);
  564. // Peer is not responsive. Remove it from the greylist.
  565. greylist.remove(position);
  566. debug!(target: "net::hosts::refresh_greylist()", "Peer {} is not response. Removed from greylist", url);
  567. }
  568. }
  569. }
  570. Err(e) => {
  571. debug!(target: "net::hosts::probe_node()", "Failed to connect to {}, ({})", url, e);
  572. // Peer is not responsive. Remove it from the greylist.
  573. greylist.remove(position);
  574. debug!(target: "net::hosts::refresh_greylist()", "Peer {} is not response. Removed from greylist", url);
  575. }
  576. }
  577. // TODO: create a custom net setting for this timer
  578. sleep(p2p.settings().outbound_peer_discovery_attempt_time).await;
  579. }
  580. }
  581. //async fn wait(&self) -> bool {
  582. // let wakeup_start = Instant::now();
  583. // self.wakeup_self.wait().await;
  584. // let wakeup_end = Instant::now();
  585. // let epsilon = Duration::from_millis(200);
  586. // wakeup_end - wakeup_start <= epsilon
  587. //}
  588. //fn notify(&self) {
  589. // self.wakeup_self.notify()
  590. //}
  591. fn session(&self) -> OutboundSessionPtr {
  592. self.session.upgrade()
  593. }
  594. fn p2p(&self) -> P2pPtr {
  595. self.session().p2p()
  596. }
  597. //fn hosts(&self) -> HostsPtr {
  598. // self.session().p2p().hosts()
  599. //}
  600. }