ckb_network/
network.rs

1//! Global state struct and start function
2use crate::errors::Error;
3#[cfg(not(target_family = "wasm"))]
4use crate::errors::P2PError;
5use crate::peer_registry::{ConnectionStatus, PeerRegistry};
6use crate::peer_store::{
7    PeerStore,
8    types::{AddrInfo, BannedAddr},
9};
10use crate::protocols::{
11    disconnect_message::DisconnectMessageProtocol,
12    discovery::{DiscoveryAddressManager, DiscoveryProtocol},
13    feeler::Feeler,
14    identify::{Flags, IdentifyCallback, IdentifyProtocol},
15    ping::PingHandler,
16    support_protocols::SupportProtocols,
17};
18use crate::services::{
19    dump_peer_store::DumpPeerStoreService, outbound_peer::OutboundPeerService,
20    protocol_type_checker::ProtocolTypeCheckerService,
21};
22use crate::{Behaviour, CKBProtocol, Peer, PeerIndex, ProtocolId, ServiceControl};
23use ckb_app_config::{NetworkConfig, SupportProtocol, default_support_all_protocols};
24use ckb_logger::{debug, error, info, trace, warn};
25use ckb_spawn::Spawn;
26use ckb_stop_handler::{CancellationToken, broadcast_exit_signals, new_tokio_exit_rx};
27use ckb_systemtime::{Duration, Instant};
28use ckb_util::{Condvar, Mutex, RwLock};
29use futures::{Future, channel::mpsc::Sender};
30use ipnetwork::IpNetwork;
31use p2p::{
32    SessionId, async_trait,
33    builder::ServiceBuilder,
34    bytes::Bytes,
35    context::{ServiceContext, SessionContext},
36    error::{DialerErrorKind, HandshakeErrorKind, ProtocolHandleErrorKind, SendErrorKind},
37    multiaddr::{Multiaddr, Protocol},
38    secio::{self, PeerId, SecioKeyPair, error::SecioError},
39    service::{
40        ProtocolHandle, Service, ServiceAsyncControl, ServiceError, ServiceEvent, TargetProtocol,
41        TargetSession,
42    },
43    traits::ServiceHandle,
44    utils::{extract_peer_id, is_reachable, multiaddr_to_socketaddr},
45    yamux::config::Config as YamuxConfig,
46};
47use rand::prelude::IteratorRandom;
48#[cfg(feature = "with_sentry")]
49use sentry::{Level, capture_message, with_scope};
50#[cfg(not(target_family = "wasm"))]
51use std::sync::mpsc;
52use std::{
53    borrow::Cow,
54    cmp::max,
55    collections::{HashMap, HashSet},
56    pin::Pin,
57    sync::{
58        Arc,
59        atomic::{AtomicBool, Ordering},
60    },
61    thread,
62};
63use tokio::{self, sync::oneshot};
64
65const P2P_SEND_TIMEOUT: Duration = Duration::from_secs(6);
66const P2P_TRY_SEND_INTERVAL: Duration = Duration::from_millis(100);
67// After 5 minutes we consider this dial hang
68const DIAL_HANG_TIMEOUT: Duration = Duration::from_secs(300);
69
70/// The global shared state of the network module
71pub struct NetworkState {
72    pub(crate) peer_registry: RwLock<PeerRegistry>,
73    pub(crate) peer_store: Mutex<PeerStore>,
74    /// Node listened addresses
75    pub(crate) listened_addrs: RwLock<Vec<Multiaddr>>,
76    dialing_addrs: RwLock<HashMap<PeerId, Instant>>,
77    /// Node public addresses by config
78    public_addrs: HashSet<Multiaddr>,
79    observed_addrs: RwLock<HashMap<PeerIndex, Multiaddr>>,
80    local_private_key: secio::SecioKeyPair,
81    local_peer_id: PeerId,
82    pub(crate) bootnodes: Vec<Multiaddr>,
83    pub(crate) config: NetworkConfig,
84    pub(crate) active: AtomicBool,
85    /// Node supported protocols
86    /// fields: ProtocolId, Protocol Name, Supported Versions
87    pub(crate) protocols: RwLock<Vec<(ProtocolId, String, Vec<String>)>>,
88    pub(crate) required_flags: Flags,
89
90    pub(crate) ckb2023: AtomicBool,
91}
92
93impl NetworkState {
94    /// Init from config
95    #[cfg(not(target_family = "wasm"))]
96    pub fn from_config(config: NetworkConfig) -> Result<NetworkState, Error> {
97        config.create_dir_if_not_exists()?;
98        let local_private_key = config.fetch_private_key()?;
99        let local_peer_id = local_private_key.peer_id();
100        // set max score to public addresses
101        let public_addrs: HashSet<Multiaddr> = config
102            .listen_addresses
103            .iter()
104            .chain(config.public_addresses.iter())
105            .cloned()
106            .filter_map(|mut addr| match multiaddr_to_socketaddr(&addr) {
107                Some(socket_addr) if !is_reachable(socket_addr.ip()) => None,
108                _ => {
109                    match extract_peer_id(&addr) {
110                        Some(peer_id) if peer_id != local_peer_id => {
111                            error!("Don't include addresses that not associated with this node in the public_addresses list: {:?}", addr);
112                            std::process::exit(1);
113                        }
114                        Some(_) => (),
115                        None => addr.push(Protocol::P2P(Cow::Borrowed(local_peer_id.as_bytes()))),
116                    }
117                    Some(addr)
118                }
119            })
120            .collect();
121        info!("Loading the peer store. This process may take a few seconds to complete.");
122
123        let peer_store = Mutex::new(PeerStore::load_from_dir_or_default(
124            config.peer_store_path(),
125        ));
126        let bootnodes = config.bootnodes();
127
128        let peer_registry = PeerRegistry::new(
129            config.max_inbound_peers(),
130            config.max_outbound_peers(),
131            config.whitelist_only,
132            config.whitelist_peers(),
133        );
134
135        Ok(NetworkState {
136            peer_store,
137            config,
138            bootnodes,
139            peer_registry: RwLock::new(peer_registry),
140            dialing_addrs: RwLock::new(HashMap::default()),
141            public_addrs,
142            listened_addrs: RwLock::new(Vec::new()),
143            observed_addrs: RwLock::new(HashMap::default()),
144            local_private_key,
145            local_peer_id,
146            active: AtomicBool::new(true),
147            protocols: RwLock::new(Vec::new()),
148            required_flags: Flags::SYNC | Flags::DISCOVERY | Flags::RELAY,
149            ckb2023: AtomicBool::new(false),
150        })
151    }
152
153    #[cfg(target_family = "wasm")]
154    pub async fn from_config(config: NetworkConfig) -> Result<NetworkState, Error> {
155        let local_private_key = config.fetch_private_key()?;
156        let local_peer_id = local_private_key.peer_id();
157        // set max score to public addresses
158        let public_addrs: HashSet<Multiaddr> = config
159            .listen_addresses
160            .iter()
161            .chain(config.public_addresses.iter())
162            .cloned()
163            .filter_map(|mut addr| match multiaddr_to_socketaddr(&addr) {
164                Some(socket_addr) if !is_reachable(socket_addr.ip()) => None,
165                _ => {
166                    if extract_peer_id(&addr).is_none() {
167                        addr.push(Protocol::P2P(Cow::Borrowed(local_peer_id.as_bytes())));
168                    }
169                    Some(addr)
170                }
171            })
172            .collect();
173        info!("Loading the peer store. This process may take a few seconds to complete.");
174        let peer_store = Mutex::new(PeerStore::load_from_idb(config.peer_store_path()).await);
175        let bootnodes = config.bootnodes();
176
177        let peer_registry = PeerRegistry::new(
178            config.max_inbound_peers(),
179            config.max_outbound_peers(),
180            config.whitelist_only,
181            config.whitelist_peers(),
182        );
183        Ok(NetworkState {
184            peer_store,
185            config,
186            bootnodes,
187            peer_registry: RwLock::new(peer_registry),
188            dialing_addrs: RwLock::new(HashMap::default()),
189            public_addrs,
190            listened_addrs: RwLock::new(Vec::new()),
191            observed_addrs: RwLock::new(HashMap::default()),
192            local_private_key,
193            local_peer_id,
194            active: AtomicBool::new(true),
195            protocols: RwLock::new(Vec::new()),
196            required_flags: Flags::SYNC | Flags::DISCOVERY | Flags::RELAY,
197            ckb2023: AtomicBool::new(false),
198        })
199    }
200
201    /// fork flag
202    pub fn ckb2023(self, init: bool) -> Self {
203        self.ckb2023.store(init, Ordering::SeqCst);
204        self
205    }
206
207    /// use to discovery get nodes message to announce what kind of node information need from the other peer
208    /// default with `Flags::SYNC | Flags::DISCOVERY | Flags::RELAY`
209    pub fn required_flags(mut self, flags: Flags) -> Self {
210        self.required_flags = flags;
211        self
212    }
213
214    pub(crate) fn report_session(
215        &self,
216        p2p_control: &ServiceControl,
217        session_id: SessionId,
218        behaviour: Behaviour,
219    ) {
220        if let Some(addr) = self.with_peer_registry(|reg| {
221            reg.get_peer(session_id)
222                .filter(|peer| !peer.is_whitelist)
223                .map(|peer| peer.connected_addr.clone())
224        }) {
225            trace!("Report {:?} because {:?}", addr, behaviour);
226            let report_result = self.peer_store.lock().report(&addr, behaviour);
227            if report_result.is_banned() {
228                if let Err(err) = disconnect_with_message(p2p_control, session_id, "banned") {
229                    debug!("Disconnect failed {:?}, error: {:?}", session_id, err);
230                }
231            }
232        } else {
233            debug!(
234                "Report {} failure: not found in peer registry or it is on the whitelist",
235                session_id
236            );
237        }
238    }
239
240    pub(crate) fn ban_session(
241        &self,
242        p2p_control: &ServiceControl,
243        session_id: SessionId,
244        duration: Duration,
245        reason: String,
246    ) {
247        if let Some(addr) = self.with_peer_registry(|reg| {
248            reg.get_peer(session_id)
249                .filter(|peer| !peer.is_whitelist)
250                .map(|peer| peer.connected_addr.clone())
251        }) {
252            info!(
253                "Ban peer {:?} for {} seconds, reason: {}",
254                addr,
255                duration.as_secs(),
256                reason
257            );
258            if let Some(metrics) = ckb_metrics::handle() {
259                metrics.ckb_network_ban_peer.inc();
260            }
261            if let Some(peer) = self.with_peer_registry_mut(|reg| reg.remove_peer(session_id)) {
262                let message = format!("Ban for {} seconds, reason: {}", duration.as_secs(), reason);
263                self.peer_store.lock().ban_addr(
264                    &peer.connected_addr,
265                    duration.as_millis() as u64,
266                    reason,
267                );
268                if let Err(err) =
269                    disconnect_with_message(p2p_control, peer.session_id, message.as_str())
270                {
271                    debug!("Disconnect failed {:?}, error: {:?}", peer.session_id, err);
272                }
273            }
274        } else {
275            debug!(
276                "Ban session({}) failed: not found in peer registry or it is on the whitelist",
277                session_id
278            );
279        }
280    }
281
282    pub(crate) fn accept_peer(
283        &self,
284        session_context: &SessionContext,
285    ) -> Result<Option<Peer>, Error> {
286        // NOTE: be careful, here easy cause a deadlock,
287        //    because peer_store's lock scope across peer_registry's lock scope
288        let mut peer_store = self.peer_store.lock();
289        let accept_peer_result = {
290            self.peer_registry.write().accept_peer(
291                session_context.address.clone(),
292                session_context.id,
293                session_context.ty,
294                &mut peer_store,
295            )
296        };
297        accept_peer_result
298    }
299
300    /// For restrict lock in inner scope
301    pub fn with_peer_registry<F, T>(&self, callback: F) -> T
302    where
303        F: FnOnce(&PeerRegistry) -> T,
304    {
305        callback(&self.peer_registry.read())
306    }
307
308    // For restrict lock in inner scope
309    pub(crate) fn with_peer_registry_mut<F, T>(&self, callback: F) -> T
310    where
311        F: FnOnce(&mut PeerRegistry) -> T,
312    {
313        callback(&mut self.peer_registry.write())
314    }
315
316    // For restrict lock in inner scope
317    pub(crate) fn with_peer_store_mut<F, T>(&self, callback: F) -> T
318    where
319        F: FnOnce(&mut PeerStore) -> T,
320    {
321        callback(&mut self.peer_store.lock())
322    }
323
324    /// Get peer id of local node
325    pub fn local_peer_id(&self) -> &PeerId {
326        &self.local_peer_id
327    }
328
329    /// Use on test
330    pub fn local_private_key(&self) -> &secio::SecioKeyPair {
331        &self.local_private_key
332    }
333
334    /// Get local node's peer id in base58 format string
335    pub fn node_id(&self) -> String {
336        self.local_peer_id().to_base58()
337    }
338
339    pub(crate) fn public_addrs(&self, count: usize) -> Vec<Multiaddr> {
340        if self.public_addrs.len() <= count {
341            return self.public_addrs.iter().cloned().collect();
342        } else {
343            self.public_addrs
344                .iter()
345                .cloned()
346                .choose_multiple(&mut rand::thread_rng(), count)
347        }
348    }
349
350    pub(crate) fn connection_status(&self) -> ConnectionStatus {
351        self.peer_registry.read().connection_status()
352    }
353
354    /// Get local node's listen address list
355    pub fn public_urls(&self, max_urls: usize) -> Vec<(String, u8)> {
356        let listened_addrs = self.listened_addrs.read();
357        self.public_addrs(max_urls.saturating_sub(listened_addrs.len()))
358            .into_iter()
359            .filter_map(|addr| {
360                if !listened_addrs.contains(&addr) {
361                    Some((addr, 1))
362                } else {
363                    None
364                }
365            })
366            .chain(listened_addrs.iter().map(|addr| (addr.to_owned(), 1)))
367            .map(|(addr, score)| (addr.to_string(), score))
368            .collect()
369    }
370
371    pub(crate) fn add_node(&self, p2p_control: &ServiceControl, address: Multiaddr) {
372        self.dial_identify(p2p_control, address);
373    }
374
375    /// use a filter to get protocol id list
376    pub fn get_protocol_ids<F: Fn(ProtocolId) -> bool>(&self, filter: F) -> Vec<ProtocolId> {
377        self.protocols
378            .read()
379            .iter()
380            .filter_map(|&(id, _, _)| if filter(id) { Some(id) } else { None })
381            .collect::<Vec<_>>()
382    }
383
384    pub(crate) fn can_dial(&self, addr: &Multiaddr) -> bool {
385        let peer_id = extract_peer_id(addr);
386        if peer_id.is_none() {
387            error!("Do not dial addr without peer id, addr: {}", addr);
388            return false;
389        }
390        let peer_id = peer_id.as_ref().unwrap();
391
392        if self.local_peer_id() == peer_id {
393            trace!("Do not dial self: {:?}, {}", peer_id, addr);
394            return false;
395        }
396        if self.public_addrs.contains(addr) {
397            trace!(
398                "Do not dial listened address(self): {:?}, {}",
399                peer_id, addr
400            );
401            return false;
402        }
403
404        let peer_in_registry = self.with_peer_registry(|reg| {
405            reg.get_key_by_peer_id(peer_id).is_some() || reg.is_feeler(addr)
406        });
407        if peer_in_registry {
408            trace!("Do not dial peer in registry: {:?}, {}", peer_id, addr);
409            return false;
410        }
411
412        if let Some(dial_started) = self.dialing_addrs.read().get(peer_id) {
413            trace!(
414                "Do not send repeated dial commands to network service: {:?}, {}",
415                peer_id, addr
416            );
417            if Instant::now().saturating_duration_since(*dial_started) > DIAL_HANG_TIMEOUT {
418                #[cfg(feature = "with_sentry")]
419                with_scope(
420                    |scope| scope.set_fingerprint(Some(&["ckb-network", "dialing-timeout"])),
421                    || {
422                        capture_message(
423                            &format!(
424                                "Dialing {:?}, {:?} for more than {} seconds, \
425                                 something is wrong in network service",
426                                peer_id,
427                                addr,
428                                DIAL_HANG_TIMEOUT.as_secs(),
429                            ),
430                            Level::Warning,
431                        )
432                    },
433                );
434            }
435            return false;
436        }
437
438        true
439    }
440
441    pub(crate) fn dial_success(&self, addr: &Multiaddr) {
442        if let Some(peer_id) = extract_peer_id(addr) {
443            self.dialing_addrs.write().remove(&peer_id);
444        }
445    }
446
447    pub(crate) fn dial_failed(&self, addr: &Multiaddr) {
448        self.with_peer_registry_mut(|reg| {
449            reg.remove_feeler(addr);
450        });
451
452        if let Some(peer_id) = extract_peer_id(addr) {
453            self.dialing_addrs.write().remove(&peer_id);
454        }
455    }
456
457    /// Dial
458    /// return value indicates the dialing is actually sent or denied.
459    fn dial_inner(
460        &self,
461        p2p_control: &ServiceControl,
462        addr: Multiaddr,
463        target: TargetProtocol,
464    ) -> Result<(), Error> {
465        if !self.can_dial(&addr) {
466            return Err(Error::Dial(format!("ignore dialing addr {addr}")));
467        }
468
469        debug!("Dialing {addr}");
470        p2p_control.dial(addr.clone(), target)?;
471        self.dialing_addrs.write().insert(
472            extract_peer_id(&addr).expect("verified addr"),
473            Instant::now(),
474        );
475        Ok(())
476    }
477
478    /// Dial just identify protocol
479    pub fn dial_identify(&self, p2p_control: &ServiceControl, addr: Multiaddr) {
480        if let Err(err) = self.dial_inner(
481            p2p_control,
482            addr,
483            TargetProtocol::Single(SupportProtocols::Identify.protocol_id()),
484        ) {
485            debug!("dial_identify error: {err}");
486        }
487    }
488
489    /// Dial just feeler protocol
490    pub fn dial_feeler(&self, p2p_control: &ServiceControl, addr: Multiaddr) {
491        if let Err(err) = self.dial_inner(
492            p2p_control,
493            addr.clone(),
494            TargetProtocol::Single(SupportProtocols::Identify.protocol_id()),
495        ) {
496            debug!("dial_feeler error {err}");
497        } else {
498            self.with_peer_registry_mut(|reg| {
499                reg.add_feeler(&addr);
500            });
501        }
502    }
503
504    /// add observed address for identify protocol
505    pub(crate) fn add_observed_addr(&self, session_id: SessionId, addr: Multiaddr) {
506        let mut pending_observed_addrs = self.observed_addrs.write();
507        pending_observed_addrs.insert(session_id, addr);
508    }
509
510    // randomly select count addresses from observed_addrs
511    pub(crate) fn observed_addrs(&self, count: usize) -> Vec<Multiaddr> {
512        let observed_addrs = self
513            .observed_addrs
514            .read()
515            .values()
516            .cloned()
517            .collect::<HashSet<_>>();
518        if observed_addrs.len() <= count {
519            return observed_addrs.into_iter().collect();
520        } else {
521            observed_addrs
522                .into_iter()
523                .choose_multiple(&mut rand::thread_rng(), count)
524        }
525    }
526
527    /// Network message processing controller, default is true, if false, discard any received messages
528    pub fn is_active(&self) -> bool {
529        self.active.load(Ordering::Acquire)
530    }
531}
532
533/// Used to handle global events of tentacle, such as session open/close
534pub struct EventHandler {
535    pub(crate) network_state: Arc<NetworkState>,
536}
537
538impl EventHandler {
539    /// init an event handler
540    pub fn new(network_state: Arc<NetworkState>) -> Self {
541        Self { network_state }
542    }
543}
544
545/// Exit trait used to notify all other module to exit
546pub trait ExitHandler: Send + Unpin + 'static {
547    /// notify other module to exit
548    fn notify_exit(&self);
549}
550
551/// Default exit handle
552#[derive(Clone, Default)]
553pub struct DefaultExitHandler {
554    lock: Arc<Mutex<()>>,
555    exit: Arc<Condvar>,
556}
557
558impl DefaultExitHandler {
559    /// Block on current thread util exit notify
560    pub fn wait_for_exit(&self) {
561        self.exit.wait(&mut self.lock.lock());
562    }
563}
564
565impl ExitHandler for DefaultExitHandler {
566    fn notify_exit(&self) {
567        self.exit.notify_all();
568    }
569}
570
571impl EventHandler {
572    fn inbound_eviction(&self) -> Vec<PeerIndex> {
573        if self.network_state.config.bootnode_mode {
574            let status = self.network_state.connection_status();
575
576            if status.max_inbound <= status.non_whitelist_inbound.saturating_add(10) {
577                self.network_state
578                    .with_peer_registry(|registry| {
579                        registry
580                            .peers()
581                            .values()
582                            .filter(|peer| peer.is_inbound() && !peer.is_whitelist)
583                            .map(|peer| peer.session_id)
584                            .collect::<Vec<SessionId>>()
585                    })
586                    .into_iter()
587                    .enumerate()
588                    .filter_map(|(index, peer)| if index & 0x1 != 0 { Some(peer) } else { None })
589                    .collect()
590            } else {
591                Vec::new()
592            }
593        } else {
594            Vec::new()
595        }
596    }
597}
598
599#[async_trait]
600impl ServiceHandle for EventHandler {
601    async fn handle_error(&mut self, context: &mut ServiceContext, error: ServiceError) {
602        match error {
603            ServiceError::DialerError { address, error } => {
604                match error {
605                    DialerErrorKind::HandshakeError(HandshakeErrorKind::SecioError(
606                        SecioError::ConnectSelf,
607                    )) => {
608                        debug!("dial observed address success: {:?}", address);
609                    }
610                    DialerErrorKind::IoError(e)
611                        if e.kind() == std::io::ErrorKind::AddrNotAvailable =>
612                    {
613                        warn!("DialerError({}) {}", address, e);
614                    }
615                    _ => {
616                        debug!("DialerError({}) {}", address, error);
617                    }
618                }
619                self.network_state.dial_failed(&address);
620            }
621            ServiceError::ProtocolError {
622                id,
623                proto_id,
624                error,
625            } => {
626                debug!("ProtocolError({}, {}) {}", id, proto_id, error);
627                let message = format!("ProtocolError id={proto_id}");
628                // Ban because misbehave of remote peer
629                self.network_state.ban_session(
630                    &context.control().clone().into(),
631                    id,
632                    Duration::from_secs(300),
633                    message,
634                );
635            }
636            ServiceError::SessionTimeout { session_context } => {
637                debug!(
638                    "SessionTimeout({}, {})",
639                    session_context.id, session_context.address,
640                );
641            }
642            ServiceError::MuxerError {
643                session_context,
644                error,
645            } => {
646                debug!(
647                    "MuxerError({}, {}), substream error {}, disconnect it",
648                    session_context.id, session_context.address, error,
649                );
650            }
651            ServiceError::ListenError { address, error } => {
652                debug!("ListenError: address={:?}, error={:?}", address, error);
653            }
654            ServiceError::ProtocolSelectError {
655                proto_name,
656                session_context,
657            } => {
658                debug!(
659                    "ProtocolSelectError: proto_name={:?}, session_id={}",
660                    proto_name, session_context.id,
661                );
662            }
663            ServiceError::SessionBlocked { session_context } => {
664                debug!("SessionBlocked: {}", session_context.id);
665            }
666            ServiceError::ProtocolHandleError { proto_id, error } => {
667                debug!("ProtocolHandleError: {:?}, proto_id: {}", error, proto_id);
668
669                let ProtocolHandleErrorKind::AbnormallyClosed(opt_session_id) = error;
670                {
671                    if let Some(id) = opt_session_id {
672                        self.network_state.ban_session(
673                            &context.control().clone().into(),
674                            id,
675                            Duration::from_secs(300),
676                            format!("protocol {proto_id} panic when process peer message"),
677                        );
678                    }
679                    #[cfg(feature = "with_sentry")]
680                    with_scope(
681                        |scope| scope.set_fingerprint(Some(&["ckb-network", "p2p-service-error"])),
682                        || {
683                            capture_message(
684                                &format!(
685                                    "ProtocolHandleError: AbnormallyClosed, proto_id: {opt_session_id:?}, session id: {opt_session_id:?}"
686                                ),
687                                Level::Warning,
688                            )
689                        },
690                    );
691                    error!(
692                        "ProtocolHandleError: AbnormallyClosed, proto_id: {opt_session_id:?}, session id: {opt_session_id:?}"
693                    );
694
695                    broadcast_exit_signals();
696                }
697            }
698        }
699    }
700
701    async fn handle_event(&mut self, context: &mut ServiceContext, event: ServiceEvent) {
702        // When session disconnect update status anyway
703        match event {
704            ServiceEvent::SessionOpen { session_context } => {
705                debug!(
706                    "SessionOpen({}, {})",
707                    session_context.id, session_context.address,
708                );
709
710                self.network_state.dial_success(&session_context.address);
711
712                let iter = self.inbound_eviction();
713
714                let control = context.control().clone().into();
715
716                for peer in iter {
717                    if let Err(err) =
718                        disconnect_with_message(&control, peer, "bootnode random eviction")
719                    {
720                        debug!("Inbound eviction failed {:?}, error: {:?}", peer, err);
721                    }
722                }
723
724                if self
725                    .network_state
726                    .with_peer_registry(|reg| reg.is_feeler(&session_context.address))
727                {
728                    debug!(
729                        "Feeler connected {} => {}",
730                        session_context.id, session_context.address,
731                    );
732                } else {
733                    match self.network_state.accept_peer(&session_context) {
734                        Ok(Some(evicted_peer)) => {
735                            debug!(
736                                "Disconnect peer, {} => {}",
737                                evicted_peer.session_id, evicted_peer.connected_addr,
738                            );
739                            if let Err(err) = disconnect_with_message(
740                                &control,
741                                evicted_peer.session_id,
742                                "evict because accepted better peer",
743                            ) {
744                                debug!(
745                                    "Disconnect failed {:?}, error: {:?}",
746                                    evicted_peer.session_id, err
747                                );
748                            }
749                        }
750                        Ok(None) => debug!(
751                            "{} open, registry {} success",
752                            session_context.id, session_context.address,
753                        ),
754                        Err(err) => {
755                            debug!(
756                                "Peer registry failed {:?}. Disconnect {} => {}",
757                                err, session_context.id, session_context.address,
758                            );
759                            if let Err(err) = disconnect_with_message(
760                                &control,
761                                session_context.id,
762                                "reject peer connection",
763                            ) {
764                                debug!(
765                                    "Disconnect failed {:?}, error: {:?}",
766                                    session_context.id, err
767                                );
768                            }
769                        }
770                    }
771                }
772            }
773            ServiceEvent::SessionClose { session_context } => {
774                debug!(
775                    "SessionClose({}, {})",
776                    session_context.id, session_context.address,
777                );
778                let peer_exists = self.network_state.with_peer_registry_mut(|reg| {
779                    // should make sure feelers is clean
780                    reg.remove_feeler(&session_context.address);
781                    reg.remove_peer(session_context.id).is_some()
782                });
783                if peer_exists {
784                    debug!(
785                        "{} closed. Remove {} from peer_registry",
786                        session_context.id, session_context.address,
787                    );
788                    self.network_state.with_peer_store_mut(|peer_store| {
789                        peer_store.remove_disconnected_peer(&session_context.address);
790                    });
791                }
792                self.network_state
793                    .observed_addrs
794                    .write()
795                    .remove(&session_context.id);
796            }
797            _ => {
798                info!("p2p service event: {:?}", event);
799            }
800        }
801    }
802}
803
804/// Ckb network service, use to start p2p network
805pub struct NetworkService {
806    p2p_service: Service<EventHandler, SecioKeyPair>,
807    network_state: Arc<NetworkState>,
808    ping_controller: Option<Sender<()>>,
809    // Background services
810    bg_services: Vec<Pin<Box<dyn Future<Output = ()> + 'static + Send>>>,
811    version: String,
812}
813
814impl NetworkService {
815    /// init with all config
816    pub fn new(
817        network_state: Arc<NetworkState>,
818        protocols: Vec<CKBProtocol>,
819        required_protocol_ids: Vec<ProtocolId>,
820        // name, version, flags
821        identify_announce: (String, String, Flags),
822        transport_type: TransportType,
823    ) -> Self {
824        let config = &network_state.config;
825
826        if config.support_protocols.iter().collect::<HashSet<_>>()
827            != default_support_all_protocols()
828                .iter()
829                .collect::<HashSet<_>>()
830        {
831            warn!(
832                "Customized supported protocols: {:?}",
833                config.support_protocols
834            );
835        }
836
837        // == Build p2p service struct
838        let mut protocol_metas = protocols
839            .into_iter()
840            .map(CKBProtocol::build)
841            .collect::<Vec<_>>();
842
843        // == Build special protocols
844
845        // Identify is a core protocol, user cannot disable it via config
846        let identify_callback = IdentifyCallback::new(
847            Arc::clone(&network_state),
848            identify_announce.0,
849            identify_announce.1.clone(),
850            identify_announce.2,
851        );
852        let identify_meta = SupportProtocols::Identify.build_meta_with_service_handle(move || {
853            ProtocolHandle::Callback(Box::new(IdentifyProtocol::new(identify_callback)))
854        });
855        protocol_metas.push(identify_meta);
856
857        // Ping protocol
858        let ping_controller = if config.support_protocols.contains(&SupportProtocol::Ping) {
859            let ping_interval = Duration::from_secs(config.ping_interval_secs);
860            let ping_timeout = Duration::from_secs(config.ping_timeout_secs);
861
862            let ping_network_state = Arc::clone(&network_state);
863            let (ping_handler, ping_controller) =
864                PingHandler::new(ping_interval, ping_timeout, ping_network_state);
865            let ping_meta = SupportProtocols::Ping.build_meta_with_service_handle(move || {
866                ProtocolHandle::Callback(Box::new(ping_handler))
867            });
868            protocol_metas.push(ping_meta);
869            Some(ping_controller)
870        } else {
871            None
872        };
873
874        // Discovery protocol
875        if config
876            .support_protocols
877            .contains(&SupportProtocol::Discovery)
878        {
879            let addr_mgr = DiscoveryAddressManager {
880                network_state: Arc::clone(&network_state),
881                discovery_local_address: config.discovery_local_address,
882            };
883            let disc_meta = SupportProtocols::Discovery.build_meta_with_service_handle(move || {
884                ProtocolHandle::Callback(Box::new(DiscoveryProtocol::new(
885                    addr_mgr,
886                    config
887                        .discovery_announce_check_interval_secs
888                        .map(Duration::from_secs),
889                )))
890            });
891            protocol_metas.push(disc_meta);
892        }
893
894        // Feeler protocol
895        if config.support_protocols.contains(&SupportProtocol::Feeler) {
896            let feeler_meta = SupportProtocols::Feeler.build_meta_with_service_handle({
897                let network_state = Arc::clone(&network_state);
898                move || ProtocolHandle::Callback(Box::new(Feeler::new(Arc::clone(&network_state))))
899            });
900            protocol_metas.push(feeler_meta);
901        }
902
903        // DisconnectMessage protocol
904        if config
905            .support_protocols
906            .contains(&SupportProtocol::DisconnectMessage)
907        {
908            let disconnect_message_state = Arc::clone(&network_state);
909            let disconnect_message_meta = SupportProtocols::DisconnectMessage
910                .build_meta_with_service_handle(move || {
911                    ProtocolHandle::Callback(Box::new(DisconnectMessageProtocol::new(
912                        disconnect_message_state,
913                    )))
914                });
915            protocol_metas.push(disconnect_message_meta);
916        }
917
918        // HolePunching protocol
919        #[cfg(not(target_family = "wasm"))]
920        if config
921            .support_protocols
922            .contains(&SupportProtocol::HolePunching)
923        {
924            let hole_punching_state = Arc::clone(&network_state);
925            let hole_punching_meta =
926                SupportProtocols::HolePunching.build_meta_with_service_handle(move || {
927                    ProtocolHandle::Callback(Box::new(
928                        crate::protocols::hole_punching::HolePunching::new(hole_punching_state),
929                    ))
930                });
931            protocol_metas.push(hole_punching_meta);
932        }
933
934        let mut service_builder = ServiceBuilder::default();
935        let yamux_config = YamuxConfig {
936            max_stream_count: protocol_metas.len(),
937            max_stream_window_size: 1024 * 1024,
938            ..Default::default()
939        };
940        for meta in protocol_metas.into_iter() {
941            network_state
942                .protocols
943                .write()
944                .push((meta.id(), meta.name(), meta.support_versions()));
945            service_builder = service_builder.insert_protocol(meta);
946        }
947        let event_handler = EventHandler {
948            network_state: Arc::clone(&network_state),
949        };
950        service_builder = service_builder
951            .handshake_type(network_state.local_private_key.clone().into())
952            .yamux_config(yamux_config)
953            .forever(true)
954            .max_connection_number(1024)
955            .set_send_buffer_size(config.max_send_buffer())
956            .set_channel_size(config.channel_size())
957            .timeout(Duration::from_secs(5));
958
959        #[cfg(not(target_family = "wasm"))]
960        {
961            service_builder = service_builder.upnp(config.upnp);
962        }
963
964        #[cfg(target_os = "linux")]
965        let p2p_service = {
966            if config.reuse_port_on_linux {
967                let iter = config.listen_addresses.iter();
968
969                #[derive(Clone, Copy, Debug, Eq, PartialEq)]
970                enum BindType {
971                    None,
972                    Ws,
973                    Tcp,
974                    Both,
975                }
976                impl BindType {
977                    fn transform(&mut self, other: TransportType) {
978                        match (&self, other) {
979                            (BindType::None, TransportType::Ws) => *self = BindType::Ws,
980                            (BindType::None, TransportType::Tcp) => *self = BindType::Tcp,
981                            (BindType::Ws, TransportType::Tcp) => *self = BindType::Both,
982                            (BindType::Tcp, TransportType::Ws) => *self = BindType::Both,
983                            _ => (),
984                        }
985                    }
986
987                    fn is_ready(&self) -> bool {
988                        // should change to Both if ckb enable ws
989                        matches!(self, BindType::Both)
990                    }
991                }
992
993                let mut init = BindType::None;
994
995                for multi_addr in iter {
996                    if init.is_ready() {
997                        break;
998                    }
999                    match find_type(multi_addr) {
1000                        TransportType::Tcp => {
1001                            // only bind once
1002                            if matches!(init, BindType::Tcp) {
1003                                continue;
1004                            }
1005                            if let Some(addr) = multiaddr_to_socketaddr(multi_addr) {
1006                                let domain = socket2::Domain::for_address(addr);
1007                                let bind_fn = move |socket: p2p::service::TcpSocket, ctxt: p2p::service::TransformerContext| {
1008                                    let socket_ref = socket2::SockRef::from(&socket);
1009                                    #[cfg(all(
1010                                        unix,
1011                                        not(target_os = "solaris"),
1012                                        not(target_os = "illumos")
1013                                    ))]
1014                                    socket_ref.set_reuse_port(true)?;
1015                                    socket_ref.set_reuse_address(true)?;
1016                                    match ctxt.state {
1017                                        p2p::service::SocketState::Listen => {
1018                                            Ok(socket)
1019                                        }
1020                                        p2p::service::SocketState::Dial => {
1021                                            if socket_ref.domain()? == domain {
1022                                                socket_ref.bind(&addr.into())?;
1023                                            }
1024                                            Ok(socket)
1025                                        }
1026                                    }
1027                                };
1028                                init.transform(TransportType::Tcp);
1029                                service_builder = service_builder.tcp_config(bind_fn);
1030                            }
1031                        }
1032                        TransportType::Ws | TransportType::Wss => {
1033                            // only bind once
1034                            if matches!(init, BindType::Ws) {
1035                                continue;
1036                            }
1037                            if let Some(addr) = multiaddr_to_socketaddr(multi_addr) {
1038                                let domain = socket2::Domain::for_address(addr);
1039                                let bind_fn = move |socket: p2p::service::TcpSocket, ctxt: p2p::service::TransformerContext| {
1040                                    let socket_ref = socket2::SockRef::from(&socket);
1041                                    #[cfg(all(
1042                                        unix,
1043                                        not(target_os = "solaris"),
1044                                        not(target_os = "illumos")
1045                                    ))]
1046                                    socket_ref.set_reuse_port(true)?;
1047                                    socket_ref.set_reuse_address(true)?;
1048                                    match ctxt.state {
1049                                        p2p::service::SocketState::Listen => {
1050                                            Ok(socket)
1051                                        }
1052                                        p2p::service::SocketState::Dial => {
1053                                            if socket_ref.domain()? == domain {
1054                                                socket_ref.bind(&addr.into())?;
1055                                            }
1056                                            Ok(socket)
1057                                        }
1058                                    }
1059                                };
1060                                init.transform(TransportType::Ws);
1061                                service_builder = service_builder.tcp_config_on_ws(bind_fn);
1062                            }
1063                        }
1064                    }
1065                }
1066            }
1067
1068            service_builder.build(event_handler)
1069        };
1070
1071        #[cfg(not(target_os = "linux"))]
1072        // The default permissions of Windows are not enough to enable this function,
1073        // and the administrator permissions of group permissions must be turned on.
1074        // This operation is very burdensome for windows users, so it is turned off by default
1075        //
1076        // The integration test fails after MacOS is turned on, the behavior is different from linux.
1077        // Decision to turn off it
1078        let p2p_service = service_builder.build(event_handler);
1079
1080        // == Build background service tasks
1081        let dump_peer_store_service = DumpPeerStoreService::new(Arc::clone(&network_state));
1082        let protocol_type_checker_service = ProtocolTypeCheckerService::new(
1083            Arc::clone(&network_state),
1084            p2p_service.control().to_owned().into(),
1085            required_protocol_ids,
1086        );
1087        let mut bg_services = vec![
1088            Box::pin(dump_peer_store_service) as Pin<Box<_>>,
1089            Box::pin(protocol_type_checker_service) as Pin<Box<_>>,
1090        ];
1091        if config.outbound_peer_service_enabled() {
1092            let outbound_peer_service = OutboundPeerService::new(
1093                Arc::clone(&network_state),
1094                p2p_service.control().to_owned().into(),
1095                Duration::from_secs(config.connect_outbound_interval_secs),
1096                transport_type,
1097            );
1098            bg_services.push(Box::pin(outbound_peer_service) as Pin<Box<_>>);
1099        };
1100
1101        #[cfg(feature = "with_dns_seeding")]
1102        if config.dns_seeding_service_enabled() {
1103            let dns_seeding_service = crate::services::dns_seeding::DnsSeedingService::new(
1104                Arc::clone(&network_state),
1105                config.dns_seeds.clone(),
1106            );
1107            bg_services.push(Box::pin(dns_seeding_service.start()) as Pin<Box<_>>);
1108        };
1109
1110        NetworkService {
1111            p2p_service,
1112            network_state,
1113            ping_controller,
1114            bg_services,
1115            version: identify_announce.1,
1116        }
1117    }
1118
1119    /// Start the network in the background and return a controller
1120    pub fn start<S: Spawn>(self, handle: &S) -> Result<NetworkController, Error> {
1121        let config = self.network_state.config.clone();
1122
1123        let p2p_control: ServiceControl = self.p2p_service.control().to_owned().into();
1124
1125        // dial whitelist_nodes
1126        for addr in self.network_state.config.whitelist_peers() {
1127            debug!("Dial whitelist_peers {:?}", addr);
1128            self.network_state.dial_identify(&p2p_control, addr);
1129        }
1130
1131        let target = &self.network_state.required_flags;
1132
1133        // get bootnodes
1134        // try get addrs from peer_store, if peer_store have no enough addrs then use bootnodes
1135        let bootnodes = self.network_state.with_peer_store_mut(|peer_store| {
1136            let count = max((config.max_outbound_peers >> 1) as usize, 1);
1137            let mut addrs: Vec<_> = peer_store
1138                .fetch_addrs_to_attempt(count, *target, |_| true)
1139                .into_iter()
1140                .map(|paddr| paddr.addr)
1141                .collect();
1142            // Get bootnodes randomly
1143            let bootnodes = self
1144                .network_state
1145                .bootnodes
1146                .iter()
1147                .choose_multiple(&mut rand::thread_rng(), count.saturating_sub(addrs.len()))
1148                .into_iter()
1149                .cloned();
1150            addrs.extend(bootnodes);
1151            addrs
1152        });
1153
1154        // dial half bootnodes
1155        for addr in bootnodes {
1156            debug!("Dial bootnode {:?}", addr);
1157            self.network_state.dial_identify(&p2p_control, addr);
1158        }
1159
1160        let Self {
1161            mut p2p_service,
1162            network_state,
1163            ping_controller,
1164            bg_services,
1165            version,
1166        } = self;
1167
1168        // NOTE: for ensure background task finished
1169        let (bg_signals, bg_receivers): (Vec<_>, Vec<_>) = bg_services
1170            .into_iter()
1171            .map(|bg_service| {
1172                let (signal_sender, signal_receiver) = oneshot::channel::<()>();
1173                (signal_sender, (bg_service, signal_receiver))
1174            })
1175            .unzip();
1176
1177        let receiver: CancellationToken = new_tokio_exit_rx();
1178        #[cfg(not(target_family = "wasm"))]
1179        let (start_sender, start_receiver) = mpsc::channel();
1180        {
1181            #[cfg(not(target_family = "wasm"))]
1182            let network_state = Arc::clone(&network_state);
1183            let p2p_control: ServiceAsyncControl = p2p_control.clone().into();
1184            handle.spawn_task(async move {
1185                #[cfg(not(target_family = "wasm"))]
1186                {
1187                    let listen_addresses = {
1188                        let mut addresses = config.listen_addresses.clone();
1189                        if config.reuse_tcp_with_ws {
1190                            let ws_listens = addresses
1191                                .iter()
1192                                .cloned()
1193                                .filter_map(|mut addr| {
1194                                    if matches!(find_type(&addr), TransportType::Tcp) {
1195                                        addr.push(Protocol::Ws);
1196                                        Some(addr)
1197                                    } else {
1198                                        None
1199                                    }
1200                                })
1201                                .collect::<Vec<_>>();
1202
1203                            addresses.extend(ws_listens);
1204                        }
1205                        let mut addresses = addresses
1206                            .into_iter()
1207                            .collect::<HashSet<_>>()
1208                            .into_iter()
1209                            .collect::<Vec<_>>();
1210                        addresses.sort_by(|a, b| {
1211                            let ty_a = find_type(a);
1212                            let ty_b = find_type(b);
1213
1214                            ty_a.cmp(&ty_b)
1215                        });
1216
1217                        addresses
1218                    };
1219
1220                    for addr in &listen_addresses {
1221                        match p2p_service.listen(addr.to_owned()).await {
1222                            Ok(listen_address) => {
1223                                info!("Listen on address: {}", listen_address);
1224                                network_state
1225                                    .listened_addrs
1226                                    .write()
1227                                    .push(listen_address.clone());
1228                            }
1229                            Err(err) => {
1230                                warn!(
1231                                    "Listen on address {} failed, due to error: {}",
1232                                    addr.clone(),
1233                                    err
1234                                );
1235                                start_sender
1236                                    .send(Err(Error::P2P(P2PError::Transport(err))))
1237                                    .expect("channel abnormal shutdown");
1238                                return;
1239                            }
1240                        };
1241                    }
1242                    start_sender.send(Ok(())).unwrap();
1243                }
1244
1245                p2p::runtime::spawn(async move { p2p_service.run().await });
1246                tokio::select! {
1247                    _ = receiver.cancelled() => {
1248                        info!("NetworkService receive exit signal, start shutdown...");
1249                        let _ = p2p_control.shutdown().await;
1250                        // Drop senders to stop all corresponding background task
1251                        drop(bg_signals);
1252
1253                        info!("NetworkService shutdown now");
1254                    },
1255                    else => {
1256                        let _ = p2p_control.shutdown().await;
1257                        // Drop senders to stop all corresponding background task
1258                        drop(bg_signals);
1259                    },
1260                }
1261            });
1262        }
1263        for (mut service, mut receiver) in bg_receivers {
1264            handle.spawn_task(async move {
1265                loop {
1266                    tokio::select! {
1267                        _ = &mut service => {},
1268                        _ = &mut receiver => break
1269                    }
1270                }
1271            });
1272        }
1273        #[cfg(not(target_family = "wasm"))]
1274        if let Ok(Err(e)) = start_receiver.recv() {
1275            return Err(e);
1276        }
1277
1278        Ok(NetworkController {
1279            version,
1280            network_state,
1281            p2p_control,
1282            ping_controller,
1283        })
1284    }
1285}
1286
1287/// Network controller
1288#[derive(Clone)]
1289pub struct NetworkController {
1290    version: String,
1291    network_state: Arc<NetworkState>,
1292    p2p_control: ServiceControl,
1293    ping_controller: Option<Sender<()>>,
1294}
1295
1296impl NetworkController {
1297    /// Set ckb2023 start
1298    pub fn init_ckb2023(&self) {
1299        self.network_state.ckb2023.store(true, Ordering::SeqCst);
1300    }
1301
1302    /// Get ckb2023 flag
1303    pub fn load_ckb2023(&self) -> bool {
1304        self.network_state.ckb2023.load(Ordering::SeqCst)
1305    }
1306
1307    /// Node listen address list
1308    pub fn public_urls(&self, max_urls: usize) -> Vec<(String, u8)> {
1309        self.network_state.public_urls(max_urls)
1310    }
1311
1312    /// ckb version
1313    pub fn version(&self) -> &String {
1314        &self.version
1315    }
1316
1317    /// Node peer id's base58 format string
1318    pub fn node_id(&self) -> String {
1319        self.network_state.node_id()
1320    }
1321
1322    /// p2p service control
1323    pub fn p2p_control(&self) -> &ServiceControl {
1324        &self.p2p_control
1325    }
1326
1327    /// Dial remote node
1328    pub fn add_node(&self, address: Multiaddr) {
1329        self.network_state.add_node(&self.p2p_control, address)
1330    }
1331
1332    /// Disconnect session with peer id
1333    pub fn remove_node(&self, peer_id: &PeerId) {
1334        if let Some(session_id) = self
1335            .network_state
1336            .peer_registry
1337            .read()
1338            .get_key_by_peer_id(peer_id)
1339        {
1340            if let Err(err) =
1341                disconnect_with_message(&self.p2p_control, session_id, "disconnect manually")
1342            {
1343                debug!("Disconnect failed {:?}, error: {:?}", session_id, err);
1344            }
1345        } else {
1346            error!("Cannot find peer {:?}", peer_id);
1347        }
1348    }
1349
1350    /// Get banned peer list
1351    pub fn get_banned_addrs(&self) -> Vec<BannedAddr> {
1352        self.network_state
1353            .peer_store
1354            .lock()
1355            .ban_list()
1356            .get_banned_addrs()
1357    }
1358
1359    /// Clear banned list
1360    pub fn clear_banned_addrs(&self) {
1361        self.network_state.peer_store.lock().clear_ban_list();
1362    }
1363
1364    /// Get address info from peer store
1365    pub fn addr_info(&self, addr: &Multiaddr) -> Option<AddrInfo> {
1366        self.network_state
1367            .peer_store
1368            .lock()
1369            .addr_manager()
1370            .get(addr)
1371            .cloned()
1372    }
1373
1374    /// Ban an ip
1375    pub fn ban(&self, address: IpNetwork, ban_until: u64, ban_reason: String) {
1376        self.disconnect_peers_in_ip_range(address, &ban_reason);
1377        self.network_state
1378            .peer_store
1379            .lock()
1380            .ban_network(address, ban_until, ban_reason)
1381    }
1382
1383    /// Unban an ip
1384    pub fn unban(&self, address: &IpNetwork) {
1385        self.network_state
1386            .peer_store
1387            .lock()
1388            .mut_ban_list()
1389            .unban_network(address);
1390    }
1391
1392    /// Return all connected peers' information
1393    pub fn connected_peers(&self) -> Vec<(PeerIndex, Peer)> {
1394        self.network_state.with_peer_registry(|reg| {
1395            reg.peers()
1396                .iter()
1397                .map(|(peer_index, peer)| (*peer_index, peer.clone()))
1398                .collect::<Vec<_>>()
1399        })
1400    }
1401
1402    /// Ban an peer through peer index
1403    pub fn ban_peer(&self, peer_index: PeerIndex, duration: Duration, reason: String) {
1404        self.network_state
1405            .ban_session(&self.p2p_control, peer_index, duration, reason);
1406    }
1407
1408    /// disconnect peers with matched peer_ip or peer_ip_network, eg: 192.168.0.2 or 192.168.0.0/24
1409    fn disconnect_peers_in_ip_range(&self, address: IpNetwork, reason: &str) {
1410        self.network_state.with_peer_registry(|reg| {
1411            reg.peers().iter().for_each(|(peer_index, peer)| {
1412                if let Some(addr) = multiaddr_to_socketaddr(&peer.connected_addr) {
1413                    if address.contains(addr.ip()) {
1414                        let _ = disconnect_with_message(
1415                            &self.p2p_control,
1416                            *peer_index,
1417                            &format!("Ban peer {}, reason: {}", addr.ip(), reason),
1418                        );
1419                    }
1420                }
1421            })
1422        });
1423    }
1424
1425    fn try_broadcast(
1426        &self,
1427        quick: bool,
1428        target: Option<SessionId>,
1429        proto_id: ProtocolId,
1430        data: Bytes,
1431    ) -> Result<(), SendErrorKind> {
1432        let now = Instant::now();
1433        loop {
1434            let target = target
1435                .map(TargetSession::Single)
1436                .unwrap_or(TargetSession::All);
1437            let result = if quick {
1438                self.p2p_control
1439                    .quick_filter_broadcast(target, proto_id, data.clone())
1440            } else {
1441                self.p2p_control
1442                    .filter_broadcast(target, proto_id, data.clone())
1443            };
1444            match result {
1445                Ok(()) => {
1446                    return Ok(());
1447                }
1448                Err(SendErrorKind::WouldBlock) => {
1449                    if Instant::now().saturating_duration_since(now) > P2P_SEND_TIMEOUT {
1450                        warn!("Broadcast message to {} timeout", proto_id);
1451                        return Err(SendErrorKind::WouldBlock);
1452                    }
1453                    thread::sleep(P2P_TRY_SEND_INTERVAL);
1454                }
1455                Err(err) => {
1456                    warn!("Broadcast message to {} failed: {:?}", proto_id, err);
1457                    return Err(err);
1458                }
1459            }
1460        }
1461    }
1462
1463    /// Broadcast a message to all connected peers
1464    pub fn broadcast(&self, proto_id: ProtocolId, data: Bytes) -> Result<(), SendErrorKind> {
1465        self.try_broadcast(false, None, proto_id, data)
1466    }
1467
1468    /// Broadcast a message to all connected peers through quick queue
1469    pub fn quick_broadcast(&self, proto_id: ProtocolId, data: Bytes) -> Result<(), SendErrorKind> {
1470        self.try_broadcast(true, None, proto_id, data)
1471    }
1472
1473    /// Send message to one connected peer
1474    pub fn send_message_to(
1475        &self,
1476        session_id: SessionId,
1477        proto_id: ProtocolId,
1478        data: Bytes,
1479    ) -> Result<(), SendErrorKind> {
1480        self.try_broadcast(false, Some(session_id), proto_id, data)
1481    }
1482
1483    /// network message processing controller, always true, if false, discard any received messages
1484    pub fn is_active(&self) -> bool {
1485        self.network_state.is_active()
1486    }
1487
1488    /// Change active status, if set false discard any received messages
1489    pub fn set_active(&self, active: bool) {
1490        self.network_state.active.store(active, Ordering::Release);
1491    }
1492
1493    /// Return all connected peers' protocols info
1494    pub fn protocols(&self) -> Vec<(ProtocolId, String, Vec<String>)> {
1495        self.network_state.protocols.read().clone()
1496    }
1497
1498    /// Try ping all connected peers
1499    pub fn ping_peers(&self) {
1500        if let Some(mut ping_controller) = self.ping_controller.clone() {
1501            let _ignore = ping_controller.try_send(());
1502        }
1503    }
1504}
1505
1506// Send an optional message before disconnect a peer
1507pub(crate) fn disconnect_with_message(
1508    control: &ServiceControl,
1509    peer_index: SessionId,
1510    message: &str,
1511) -> Result<(), SendErrorKind> {
1512    if !message.is_empty() {
1513        let data = Bytes::from(message.as_bytes().to_vec());
1514        // Must quick send, otherwise this message will be dropped.
1515        control.quick_send_message_to(
1516            peer_index,
1517            SupportProtocols::DisconnectMessage.protocol_id(),
1518            data,
1519        )?;
1520    }
1521    control.disconnect(peer_index)
1522}
1523
1524pub(crate) async fn async_disconnect_with_message(
1525    control: &ServiceAsyncControl,
1526    peer_index: SessionId,
1527    message: &str,
1528) -> Result<(), SendErrorKind> {
1529    if !message.is_empty() {
1530        let data = Bytes::from(message.as_bytes().to_vec());
1531        // Must quick send, otherwise this message will be dropped.
1532        control
1533            .quick_send_message_to(
1534                peer_index,
1535                SupportProtocols::DisconnectMessage.protocol_id(),
1536                data,
1537            )
1538            .await?;
1539    }
1540    control.disconnect(peer_index).await
1541}
1542
1543/// Transport type on ckb
1544#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
1545pub enum TransportType {
1546    /// Tcp
1547    Tcp,
1548    /// Ws
1549    Ws,
1550    /// Wss only on wasm
1551    Wss,
1552}
1553
1554#[allow(dead_code)]
1555pub(crate) fn find_type(addr: &Multiaddr) -> TransportType {
1556    let mut iter = addr.iter();
1557
1558    iter.find_map(|proto| match proto {
1559        Protocol::Ws => Some(TransportType::Ws),
1560        Protocol::Wss => Some(TransportType::Wss),
1561        _ => None,
1562    })
1563    .unwrap_or(TransportType::Tcp)
1564}