1mod active;
4mod conn;
5mod counter;
6mod handle;
7mod types;
8pub use types::BlockRangeInfo;
9
10use crate::{
11 message::PeerMessage,
12 metrics::SessionManagerMetrics,
13 protocol::{IntoRlpxSubProtocol, OnNotSupported, RlpxSubProtocolHandlers, RlpxSubProtocols},
14 session::active::ActiveSession,
15};
16use active::QueuedOutgoingMessages;
17use alloy_primitives::map::{FbBuildHasher, HashMap};
18use counter::SessionCounter;
19use futures::{future::Either, io, FutureExt, StreamExt};
20use reth_ecies::{stream::ECIESStream, ECIESError};
21use reth_eth_wire::{
22 errors::EthStreamError, handshake::EthRlpxHandshake, multiplex::RlpxProtocolMultiplexer,
23 BlockRangeUpdate, Capabilities, DisconnectReason, EthSnapStream, EthStream, EthVersion,
24 HelloMessageWithProtocols, NetworkPrimitives, UnauthedP2PStream, UnifiedStatus,
25 HANDSHAKE_TIMEOUT,
26};
27use reth_ethereum_forks::{ForkFilter, ForkId, ForkTransition, Head};
28use reth_metrics::common::mpsc::MeteredPollSender;
29use reth_network_api::{PeerRequest, PeerRequestSender};
30use reth_network_peers::PeerId;
31use reth_network_types::SessionsConfig;
32use reth_tasks::Runtime;
33use rustc_hash::FxHashMap;
34use secp256k1::SecretKey;
35use std::{
36 future::Future,
37 net::SocketAddr,
38 sync::{atomic::AtomicU64, Arc},
39 task::{Context, Poll},
40 time::{Duration, Instant},
41};
42use tokio::{
43 io::{AsyncRead, AsyncWrite},
44 net::TcpStream,
45 sync::{mpsc, oneshot},
46};
47use tokio_stream::wrappers::ReceiverStream;
48use tokio_util::sync::PollSender;
49use tracing::{instrument, trace};
50
51use crate::session::active::{
52 request_timeout_interval, BroadcastItemCounter, RANGE_UPDATE_INTERVAL,
53};
54pub use conn::EthRlpxConnection;
55use handle::SessionCommandSender;
56pub use handle::{
57 ActiveSessionHandle, ActiveSessionMessage, PendingSessionEvent, PendingSessionHandle,
58 SessionCommand,
59};
60pub use reth_network_api::{Direction, PeerInfo};
61
62#[derive(Debug, Clone, Copy, PartialOrd, PartialEq, Eq, Hash)]
64pub struct SessionId(usize);
65
66#[must_use = "Session Manager must be polled to process session events."]
68#[derive(Debug)]
69pub struct SessionManager<N: NetworkPrimitives> {
70 next_id: usize,
72 counter: SessionCounter,
74 initial_internal_request_timeout: Duration,
77 protocol_breach_request_timeout: Duration,
80 pending_session_timeout: Duration,
82 secret_key: SecretKey,
84 status: UnifiedStatus,
86 hello_message: HelloMessageWithProtocols,
88 fork_filter: ForkFilter,
90 session_command_buffer: usize,
92 executor: Runtime,
94 pending_sessions: FxHashMap<SessionId, PendingSessionHandle>,
99 active_sessions: HashMap<PeerId, ActiveSessionHandle<N>, FbBuildHasher<64>>,
101 pending_sessions_tx: mpsc::Sender<PendingSessionEvent<N>>,
106 pending_session_rx: ReceiverStream<PendingSessionEvent<N>>,
108 active_session_tx: MeteredPollSender<ActiveSessionMessage<N>>,
113 active_session_rx: ReceiverStream<ActiveSessionMessage<N>>,
115 extra_protocols: RlpxSubProtocols,
117 disconnections_counter: DisconnectionsCounter,
119 metrics: SessionManagerMetrics,
121 handshake: Arc<dyn EthRlpxHandshake>,
123 eth_max_message_size: usize,
125 local_range_info: BlockRangeInfo,
128 reject_block_announcements: bool,
131}
132
133impl<N: NetworkPrimitives> SessionManager<N> {
136 #[expect(clippy::too_many_arguments)]
138 pub fn new(
139 secret_key: SecretKey,
140 config: SessionsConfig,
141 executor: Runtime,
142 status: UnifiedStatus,
143 hello_message: HelloMessageWithProtocols,
144 fork_filter: ForkFilter,
145 extra_protocols: RlpxSubProtocols,
146 handshake: Arc<dyn EthRlpxHandshake>,
147 eth_max_message_size: usize,
148 reject_block_announcements: bool,
149 ) -> Self {
150 let (pending_sessions_tx, pending_sessions_rx) = mpsc::channel(config.session_event_buffer);
151 let (active_session_tx, active_session_rx) = mpsc::channel(config.session_event_buffer);
152 let active_session_tx = PollSender::new(active_session_tx);
153
154 let local_range_info = BlockRangeInfo::new(
156 status.earliest_block.unwrap_or_default(),
157 status.latest_block.unwrap_or_default(),
158 status.blockhash,
159 );
160
161 Self {
162 next_id: 0,
163 counter: SessionCounter::new(config.limits),
164 initial_internal_request_timeout: config.initial_internal_request_timeout,
165 protocol_breach_request_timeout: config.protocol_breach_request_timeout,
166 pending_session_timeout: config.pending_session_timeout,
167 secret_key,
168 status,
169 hello_message,
170 fork_filter,
171 session_command_buffer: config.session_command_buffer,
172 executor,
173 pending_sessions: Default::default(),
174 active_sessions: Default::default(),
175 pending_sessions_tx,
176 pending_session_rx: ReceiverStream::new(pending_sessions_rx),
177 active_session_tx: MeteredPollSender::new(active_session_tx, "network_active_session"),
178 active_session_rx: ReceiverStream::new(active_session_rx),
179 extra_protocols,
180 disconnections_counter: Default::default(),
181 metrics: Default::default(),
182 handshake,
183 eth_max_message_size,
184 local_range_info,
185 reject_block_announcements,
186 }
187 }
188
189 pub(crate) const fn fork_id(&self) -> ForkId {
191 self.fork_filter.current()
192 }
193
194 pub fn is_valid_fork_id(&self, fork_id: ForkId) -> bool {
197 self.fork_filter.validate(fork_id).is_ok()
198 }
199
200 const fn next_id(&mut self) -> SessionId {
202 let id = self.next_id;
203 self.next_id += 1;
204 SessionId(id)
205 }
206
207 pub const fn status(&self) -> UnifiedStatus {
209 self.status
210 }
211
212 pub const fn secret_key(&self) -> SecretKey {
214 self.secret_key
215 }
216
217 pub const fn active_sessions(
219 &self,
220 ) -> &HashMap<PeerId, ActiveSessionHandle<N>, FbBuildHasher<64>> {
221 &self.active_sessions
222 }
223
224 pub fn hello_message(&self) -> HelloMessageWithProtocols {
226 self.hello_message.clone()
227 }
228
229 pub(crate) fn add_rlpx_sub_protocol(&mut self, protocol: impl IntoRlpxSubProtocol) {
231 self.extra_protocols.push(protocol)
232 }
233
234 #[inline]
236 pub(crate) fn num_pending_connections(&self) -> usize {
237 self.pending_sessions.len()
238 }
239
240 fn spawn<F>(&self, f: F)
243 where
244 F: Future<Output = ()> + Send + 'static,
245 {
246 self.executor.spawn_task(f);
247 }
248
249 pub(crate) fn on_status_update(&mut self, head: Head) -> Option<ForkTransition> {
254 self.status.blockhash = head.hash;
255 self.status.total_difficulty = Some(head.total_difficulty);
256 let transition = self.fork_filter.set_head(head);
257 self.status.forkid = self.fork_filter.current();
258 self.status.latest_block = Some(head.number);
259
260 transition
261 }
262
263 pub(crate) fn on_incoming(
268 &mut self,
269 stream: TcpStream,
270 remote_addr: SocketAddr,
271 ) -> Result<SessionId, ExceedsSessionLimit> {
272 self.counter.ensure_pending_inbound()?;
273
274 let session_id = self.next_id();
275
276 trace!(
277 target: "net::session",
278 ?remote_addr,
279 ?session_id,
280 "new pending incoming session"
281 );
282
283 let (disconnect_tx, disconnect_rx) = oneshot::channel();
284 let pending_events = self.pending_sessions_tx.clone();
285 let secret_key = self.secret_key;
286 let hello_message = self.hello_message.clone();
287 let status = self.status;
288 let fork_filter = self.fork_filter.clone();
289 let extra_handlers = self.extra_protocols.on_incoming(remote_addr);
290 self.spawn(pending_session_with_timeout(
291 self.pending_session_timeout,
292 session_id,
293 remote_addr,
294 Direction::Incoming,
295 pending_events.clone(),
296 start_pending_incoming_session(
297 self.handshake.clone(),
298 self.eth_max_message_size,
299 disconnect_rx,
300 session_id,
301 stream,
302 pending_events,
303 remote_addr,
304 secret_key,
305 hello_message,
306 status,
307 fork_filter,
308 extra_handlers,
309 ),
310 ));
311
312 let handle = PendingSessionHandle {
313 disconnect_tx: Some(disconnect_tx),
314 direction: Direction::Incoming,
315 };
316 self.pending_sessions.insert(session_id, handle);
317 self.counter.inc_pending_inbound();
318 Ok(session_id)
319 }
320
321 pub fn dial_outbound(&mut self, remote_addr: SocketAddr, remote_peer_id: PeerId) {
323 if self.counter.ensure_pending_outbound().is_ok() {
325 let session_id = self.next_id();
326 let (disconnect_tx, disconnect_rx) = oneshot::channel();
327 let pending_events = self.pending_sessions_tx.clone();
328 let secret_key = self.secret_key;
329 let hello_message = self.hello_message.clone();
330 let fork_filter = self.fork_filter.clone();
331 let status = self.status;
332 let extra_handlers = self.extra_protocols.on_outgoing(remote_addr, remote_peer_id);
333 self.spawn(pending_session_with_timeout(
334 self.pending_session_timeout,
335 session_id,
336 remote_addr,
337 Direction::Outgoing(remote_peer_id),
338 pending_events.clone(),
339 start_pending_outbound_session(
340 self.handshake.clone(),
341 self.eth_max_message_size,
342 disconnect_rx,
343 pending_events,
344 session_id,
345 remote_addr,
346 remote_peer_id,
347 secret_key,
348 hello_message,
349 status,
350 fork_filter,
351 extra_handlers,
352 ),
353 ));
354
355 let handle = PendingSessionHandle {
356 disconnect_tx: Some(disconnect_tx),
357 direction: Direction::Outgoing(remote_peer_id),
358 };
359 self.pending_sessions.insert(session_id, handle);
360 self.counter.inc_pending_outbound();
361 }
362 }
363
364 pub fn disconnect(&self, node: PeerId, reason: Option<DisconnectReason>) {
369 if let Some(session) = self.active_sessions.get(&node) {
370 session.disconnect(reason);
371 }
372 }
373
374 pub fn disconnect_all(&self, reason: Option<DisconnectReason>) {
379 for session in self.active_sessions.values() {
380 session.disconnect(reason);
381 }
382 }
383
384 pub fn disconnect_all_pending(&mut self) {
386 for session in self.pending_sessions.values_mut() {
387 session.disconnect();
388 }
389 }
390
391 pub fn send_message(&self, peer_id: &PeerId, msg: PeerMessage<N>) {
398 if let Some(session) = self.active_sessions.get(peer_id) &&
399 !session.commands.send_message(msg)
400 {
401 self.metrics.total_outgoing_peer_messages_dropped.increment(1);
402 }
403 }
404
405 fn remove_pending_session(&mut self, id: &SessionId) -> Option<PendingSessionHandle> {
407 let session = self.pending_sessions.remove(id)?;
408 self.counter.dec_pending(&session.direction);
409 Some(session)
410 }
411
412 fn remove_active_session(&mut self, id: &PeerId) -> Option<ActiveSessionHandle<N>> {
414 let session = self.active_sessions.remove(id)?;
415 self.counter.dec_active(&session.direction);
416 Some(session)
417 }
418
419 pub(crate) fn try_disconnect_incoming_connection(
423 &self,
424 stream: TcpStream,
425 reason: DisconnectReason,
426 ) {
427 if !self.disconnections_counter.has_capacity() {
428 return
430 }
431
432 let guard = self.disconnections_counter.clone();
433 let secret_key = self.secret_key;
434
435 self.spawn(async move {
436 trace!(
437 target: "net::session",
438 "gracefully disconnecting incoming connection"
439 );
440 if let Ok(stream) = get_ecies_stream(stream, secret_key, Direction::Incoming).await {
441 let mut unauth = UnauthedP2PStream::new(stream);
442 let _ = unauth.send_disconnect(reason).await;
443 drop(guard);
444 }
445 });
446 }
447
448 pub(crate) fn poll(&mut self, cx: &mut Context<'_>) -> Poll<SessionEvent<N>> {
452 match self.active_session_rx.poll_next_unpin(cx) {
454 Poll::Pending => {}
455 Poll::Ready(None) => {
456 unreachable!("Manager holds both channel halves.")
457 }
458 Poll::Ready(Some(event)) => {
459 return match event {
460 ActiveSessionMessage::Disconnected { peer_id, remote_addr } => {
461 trace!(
462 target: "net::session",
463 ?peer_id,
464 "gracefully disconnected active session."
465 );
466 self.remove_active_session(&peer_id);
467 Poll::Ready(SessionEvent::Disconnected { peer_id, remote_addr })
468 }
469 ActiveSessionMessage::ClosedOnConnectionError {
470 peer_id,
471 remote_addr,
472 error,
473 } => {
474 trace!(target: "net::session", ?peer_id, %error,"closed session.");
475 self.remove_active_session(&peer_id);
476 Poll::Ready(SessionEvent::SessionClosedOnConnectionError {
477 remote_addr,
478 peer_id,
479 error,
480 })
481 }
482 ActiveSessionMessage::ValidMessage { peer_id, message } => {
483 Poll::Ready(SessionEvent::ValidMessage { peer_id, message })
484 }
485 ActiveSessionMessage::BadMessage { peer_id } => {
486 Poll::Ready(SessionEvent::BadMessage { peer_id })
487 }
488 ActiveSessionMessage::ProtocolBreach { peer_id } => {
489 Poll::Ready(SessionEvent::ProtocolBreach { peer_id })
490 }
491 }
492 }
493 }
494
495 let event = match self.pending_session_rx.poll_next_unpin(cx) {
497 Poll::Pending => return Poll::Pending,
498 Poll::Ready(None) => unreachable!("Manager holds both channel halves."),
499 Poll::Ready(Some(event)) => event,
500 };
501 match event {
502 PendingSessionEvent::Established {
503 session_id,
504 remote_addr,
505 local_addr,
506 peer_id,
507 capabilities,
508 mut conn,
509 status,
510 direction,
511 client_id,
512 peer_listen_port,
513 } => {
514 self.remove_pending_session(&session_id);
516
517 if self.active_sessions.contains_key(&peer_id) {
519 trace!(
520 target: "net::session",
521 ?session_id,
522 ?remote_addr,
523 ?peer_id,
524 ?direction,
525 "already connected"
526 );
527
528 self.spawn(async move {
529 let _ =
531 conn.into_inner().disconnect(DisconnectReason::AlreadyConnected).await;
532 });
533
534 return Poll::Ready(SessionEvent::AlreadyConnected {
535 peer_id,
536 remote_addr,
537 direction,
538 })
539 }
540
541 let (commands_tx, commands_rx) = mpsc::channel(self.session_command_buffer);
542 let (unbounded_tx, unbounded_rx) = mpsc::unbounded_channel();
543
544 let (to_session_tx, messages_rx) = mpsc::channel(self.session_command_buffer);
545
546 let messages = PeerRequestSender::new(peer_id, to_session_tx);
547
548 let timeout = Arc::new(AtomicU64::new(
549 self.initial_internal_request_timeout.as_millis() as u64,
550 ));
551
552 let version = conn.version();
554
555 let range_update_interval = (conn.version() >= EthVersion::Eth69).then(|| {
560 let start = tokio::time::Instant::now() + RANGE_UPDATE_INTERVAL;
561 let mut interval = tokio::time::interval_at(start, RANGE_UPDATE_INTERVAL);
562 interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
563 interval
564 });
565
566 let broadcast_items = BroadcastItemCounter::new();
572 let remote_range_info = status.block_range_update().map(|update| {
573 BlockRangeInfo::new(update.earliest, update.latest, update.latest_hash)
574 });
575
576 if self.reject_block_announcements {
577 conn.set_reject_block_announcements(true);
578 }
579
580 let session = ActiveSession {
581 next_id: 0,
582 remote_peer_id: peer_id,
583 remote_addr,
584 remote_capabilities: Arc::clone(&capabilities),
585 session_id,
586 commands_rx: ReceiverStream::new(commands_rx),
587 unbounded_rx,
588 unbounded_broadcast_msgs: self.metrics.total_unbounded_broadcast_msgs.clone(),
589 to_session_manager: self.active_session_tx.clone(),
590 pending_message_to_session: None,
591 internal_request_rx: ReceiverStream::new(messages_rx).fuse(),
592 inflight_requests: Default::default(),
593 conn,
594 queued_outgoing: QueuedOutgoingMessages::new(
595 self.metrics.queued_outgoing_messages.clone(),
596 broadcast_items.clone(),
597 ),
598 received_requests_from_remote: Default::default(),
599 internal_request_timeout_interval: request_timeout_interval(
600 self.initial_internal_request_timeout,
601 ),
602 internal_request_timeout: Arc::clone(&timeout),
603 protocol_breach_request_timeout: self.protocol_breach_request_timeout,
604 terminate_message: None,
605 range_info: remote_range_info.clone(),
606 local_range_info: self.local_range_info.clone(),
607 range_update_interval,
608 last_sent_latest_block: None,
609 };
610
611 let supports_snap = session.conn.supports_snap();
612 self.spawn(session);
613
614 let client_version = client_id.into();
615 let handle = ActiveSessionHandle {
616 status: status.clone(),
617 direction,
618 session_id,
619 remote_id: peer_id,
620 version,
621 established: Instant::now(),
622 capabilities: Arc::clone(&capabilities),
623 commands: SessionCommandSender::new(commands_tx, unbounded_tx, broadcast_items),
624 client_version: Arc::clone(&client_version),
625 remote_addr,
626 local_addr,
627 peer_listen_port,
628 };
629
630 self.active_sessions.insert(peer_id, handle);
631 self.counter.inc_active(&direction);
632
633 if direction.is_outgoing() {
634 self.metrics.total_dial_successes.increment(1);
635 }
636
637 Poll::Ready(SessionEvent::SessionEstablished {
638 peer_id,
639 remote_addr,
640 client_version,
641 version,
642 capabilities,
643 status,
644 messages,
645 direction,
646 timeout,
647 range_info: remote_range_info,
648 supports_snap,
649 })
650 }
651 PendingSessionEvent::Disconnected { remote_addr, session_id, direction, error } => {
652 trace!(
653 target: "net::session",
654 ?session_id,
655 ?remote_addr,
656 ?error,
657 "disconnected pending session"
658 );
659 self.remove_pending_session(&session_id);
660 match direction {
661 Direction::Incoming => {
662 Poll::Ready(SessionEvent::IncomingPendingSessionClosed {
663 remote_addr,
664 error,
665 })
666 }
667 Direction::Outgoing(peer_id) => {
668 Poll::Ready(SessionEvent::OutgoingPendingSessionClosed {
669 remote_addr,
670 peer_id,
671 error,
672 })
673 }
674 }
675 }
676 PendingSessionEvent::OutgoingConnectionError {
677 remote_addr,
678 session_id,
679 peer_id,
680 error,
681 } => {
682 trace!(
683 target: "net::session",
684 %error,
685 ?session_id,
686 ?remote_addr,
687 ?peer_id,
688 "connection refused"
689 );
690 self.remove_pending_session(&session_id);
691 Poll::Ready(SessionEvent::OutgoingConnectionError { remote_addr, peer_id, error })
692 }
693 PendingSessionEvent::EciesAuthError { remote_addr, session_id, error, direction } => {
694 trace!(
695 target: "net::session",
696 %error,
697 ?session_id,
698 ?remote_addr,
699 "ecies auth failed"
700 );
701 self.remove_pending_session(&session_id);
702 match direction {
703 Direction::Incoming => {
704 Poll::Ready(SessionEvent::IncomingPendingSessionClosed {
705 remote_addr,
706 error: Some(PendingSessionHandshakeError::Ecies(error)),
707 })
708 }
709 Direction::Outgoing(peer_id) => {
710 Poll::Ready(SessionEvent::OutgoingPendingSessionClosed {
711 remote_addr,
712 peer_id,
713 error: Some(PendingSessionHandshakeError::Ecies(error)),
714 })
715 }
716 }
717 }
718 }
719 }
720
721 pub(crate) fn update_advertised_block_range(&mut self, block_range_update: BlockRangeUpdate) {
729 self.status.earliest_block = Some(block_range_update.earliest);
730 self.status.latest_block = Some(block_range_update.latest);
731 self.status.blockhash = block_range_update.latest_hash;
732
733 self.local_range_info.update(
735 block_range_update.earliest,
736 block_range_update.latest,
737 block_range_update.latest_hash,
738 );
739 }
740}
741
742#[derive(Default, Debug, Clone)]
744struct DisconnectionsCounter(Arc<()>);
745
746impl DisconnectionsCounter {
747 const MAX_CONCURRENT_GRACEFUL_DISCONNECTIONS: usize = 15;
748
749 fn has_capacity(&self) -> bool {
752 Arc::strong_count(&self.0) <= Self::MAX_CONCURRENT_GRACEFUL_DISCONNECTIONS
753 }
754}
755
756#[derive(Debug)]
758pub enum SessionEvent<N: NetworkPrimitives> {
759 SessionEstablished {
763 peer_id: PeerId,
765 remote_addr: SocketAddr,
767 client_version: Arc<str>,
769 capabilities: Arc<Capabilities>,
771 version: EthVersion,
773 status: Arc<UnifiedStatus>,
775 messages: PeerRequestSender<PeerRequest<N>>,
777 direction: Direction,
779 timeout: Arc<AtomicU64>,
782 range_info: Option<BlockRangeInfo>,
784 supports_snap: bool,
786 },
787 AlreadyConnected {
789 peer_id: PeerId,
791 remote_addr: SocketAddr,
793 direction: Direction,
795 },
796 ValidMessage {
798 peer_id: PeerId,
800 message: PeerMessage<N>,
802 },
803 BadMessage {
805 peer_id: PeerId,
807 },
808 ProtocolBreach {
810 peer_id: PeerId,
812 },
813 IncomingPendingSessionClosed {
815 remote_addr: SocketAddr,
817 error: Option<PendingSessionHandshakeError>,
819 },
820 OutgoingPendingSessionClosed {
822 remote_addr: SocketAddr,
824 peer_id: PeerId,
826 error: Option<PendingSessionHandshakeError>,
828 },
829 OutgoingConnectionError {
831 remote_addr: SocketAddr,
833 peer_id: PeerId,
835 error: io::Error,
837 },
838 SessionClosedOnConnectionError {
840 peer_id: PeerId,
842 remote_addr: SocketAddr,
844 error: EthStreamError,
846 },
847 Disconnected {
849 peer_id: PeerId,
851 remote_addr: SocketAddr,
853 },
854}
855
856#[derive(Debug, thiserror::Error)]
858pub enum PendingSessionHandshakeError {
859 #[error(transparent)]
861 Eth(EthStreamError),
862 #[error(transparent)]
864 Ecies(ECIESError),
865 #[error("authentication timed out")]
867 Timeout,
868 #[error("Mandatory extra capability unsupported")]
870 UnsupportedExtraCapability,
871}
872
873impl PendingSessionHandshakeError {
874 pub const fn as_disconnected(&self) -> Option<DisconnectReason> {
876 match self {
877 Self::Eth(eth_err) => eth_err.as_disconnected(),
878 _ => None,
879 }
880 }
881}
882
883#[derive(Debug, Clone, thiserror::Error)]
886#[error("session limit reached {0}")]
887pub struct ExceedsSessionLimit(pub(crate) u32);
888
889pub(crate) async fn pending_session_with_timeout<F, N: NetworkPrimitives>(
891 timeout: Duration,
892 session_id: SessionId,
893 remote_addr: SocketAddr,
894 direction: Direction,
895 events: mpsc::Sender<PendingSessionEvent<N>>,
896 f: F,
897) where
898 F: Future<Output = ()>,
899{
900 if tokio::time::timeout(timeout, f).await.is_err() {
901 trace!(target: "net::session", ?remote_addr, ?direction, "pending session timed out");
902 let event = PendingSessionEvent::Disconnected {
903 remote_addr,
904 session_id,
905 direction,
906 error: Some(PendingSessionHandshakeError::Timeout),
907 };
908 let _ = events.send(event).await;
909 }
910}
911
912#[expect(clippy::too_many_arguments)]
916pub(crate) async fn start_pending_incoming_session<N: NetworkPrimitives>(
917 handshake: Arc<dyn EthRlpxHandshake>,
918 eth_max_message_size: usize,
919 disconnect_rx: oneshot::Receiver<()>,
920 session_id: SessionId,
921 stream: TcpStream,
922 events: mpsc::Sender<PendingSessionEvent<N>>,
923 remote_addr: SocketAddr,
924 secret_key: SecretKey,
925 hello: HelloMessageWithProtocols,
926 status: UnifiedStatus,
927 fork_filter: ForkFilter,
928 extra_handlers: RlpxSubProtocolHandlers,
929) {
930 authenticate(
931 handshake,
932 eth_max_message_size,
933 disconnect_rx,
934 events,
935 stream,
936 session_id,
937 remote_addr,
938 secret_key,
939 Direction::Incoming,
940 hello,
941 status,
942 fork_filter,
943 extra_handlers,
944 )
945 .await
946}
947
948#[instrument(level = "trace", target = "net::network", skip_all, fields(%remote_addr, peer_id = ?remote_peer_id))]
950#[expect(clippy::too_many_arguments)]
951async fn start_pending_outbound_session<N: NetworkPrimitives>(
952 handshake: Arc<dyn EthRlpxHandshake>,
953 eth_max_message_size: usize,
954 disconnect_rx: oneshot::Receiver<()>,
955 events: mpsc::Sender<PendingSessionEvent<N>>,
956 session_id: SessionId,
957 remote_addr: SocketAddr,
958 remote_peer_id: PeerId,
959 secret_key: SecretKey,
960 hello: HelloMessageWithProtocols,
961 status: UnifiedStatus,
962 fork_filter: ForkFilter,
963 extra_handlers: RlpxSubProtocolHandlers,
964) {
965 let stream = match TcpStream::connect(remote_addr).await {
966 Ok(stream) => {
967 if let Err(err) = stream.set_nodelay(true) {
968 tracing::warn!(target: "net::session", "set nodelay failed: {:?}", err);
969 }
970 stream
971 }
972 Err(error) => {
973 let _ = events
974 .send(PendingSessionEvent::OutgoingConnectionError {
975 remote_addr,
976 session_id,
977 peer_id: remote_peer_id,
978 error,
979 })
980 .await;
981 return
982 }
983 };
984 authenticate(
985 handshake,
986 eth_max_message_size,
987 disconnect_rx,
988 events,
989 stream,
990 session_id,
991 remote_addr,
992 secret_key,
993 Direction::Outgoing(remote_peer_id),
994 hello,
995 status,
996 fork_filter,
997 extra_handlers,
998 )
999 .await
1000}
1001
1002#[expect(clippy::too_many_arguments)]
1004async fn authenticate<N: NetworkPrimitives>(
1005 handshake: Arc<dyn EthRlpxHandshake>,
1006 eth_max_message_size: usize,
1007 disconnect_rx: oneshot::Receiver<()>,
1008 events: mpsc::Sender<PendingSessionEvent<N>>,
1009 stream: TcpStream,
1010 session_id: SessionId,
1011 remote_addr: SocketAddr,
1012 secret_key: SecretKey,
1013 direction: Direction,
1014 hello: HelloMessageWithProtocols,
1015 status: UnifiedStatus,
1016 fork_filter: ForkFilter,
1017 extra_handlers: RlpxSubProtocolHandlers,
1018) {
1019 let local_addr = stream.local_addr().ok();
1020 let stream = match get_ecies_stream(stream, secret_key, direction).await {
1021 Ok(stream) => stream,
1022 Err(error) => {
1023 let _ = events
1024 .send(PendingSessionEvent::EciesAuthError {
1025 remote_addr,
1026 session_id,
1027 error,
1028 direction,
1029 })
1030 .await;
1031 return
1032 }
1033 };
1034
1035 let unauthed = UnauthedP2PStream::new(stream);
1036
1037 let auth = authenticate_stream(
1038 handshake,
1039 eth_max_message_size,
1040 unauthed,
1041 session_id,
1042 remote_addr,
1043 local_addr,
1044 direction,
1045 hello,
1046 status,
1047 fork_filter,
1048 extra_handlers,
1049 )
1050 .boxed();
1051
1052 match futures::future::select(disconnect_rx, auth).await {
1053 Either::Left((_, _)) => {
1054 let _ = events
1055 .send(PendingSessionEvent::Disconnected {
1056 remote_addr,
1057 session_id,
1058 direction,
1059 error: None,
1060 })
1061 .await;
1062 }
1063 Either::Right((res, _)) => {
1064 let _ = events.send(res).await;
1065 }
1066 }
1067}
1068
1069async fn get_ecies_stream<Io: AsyncRead + AsyncWrite + Unpin>(
1072 stream: Io,
1073 secret_key: SecretKey,
1074 direction: Direction,
1075) -> Result<ECIESStream<Io>, ECIESError> {
1076 match direction {
1077 Direction::Incoming => ECIESStream::incoming(stream, secret_key).await,
1078 Direction::Outgoing(remote_peer_id) => {
1079 ECIESStream::connect(stream, secret_key, remote_peer_id).await
1080 }
1081 }
1082}
1083
1084#[expect(clippy::too_many_arguments)]
1091async fn authenticate_stream<N: NetworkPrimitives>(
1092 handshake: Arc<dyn EthRlpxHandshake>,
1093 eth_max_message_size: usize,
1094 stream: UnauthedP2PStream<ECIESStream<TcpStream>>,
1095 session_id: SessionId,
1096 remote_addr: SocketAddr,
1097 local_addr: Option<SocketAddr>,
1098 direction: Direction,
1099 mut hello: HelloMessageWithProtocols,
1100 mut status: UnifiedStatus,
1101 fork_filter: ForkFilter,
1102 mut extra_handlers: RlpxSubProtocolHandlers,
1103) -> PendingSessionEvent<N> {
1104 extra_handlers.retain(|handler| hello.try_add_protocol(handler.protocol()).is_ok());
1106
1107 let (mut p2p_stream, their_hello) = match stream.handshake(hello).await {
1109 Ok(stream_res) => stream_res,
1110 Err(err) => {
1111 return PendingSessionEvent::Disconnected {
1112 remote_addr,
1113 session_id,
1114 direction,
1115 error: Some(PendingSessionHandshakeError::Eth(err.into())),
1116 }
1117 }
1118 };
1119
1120 if !extra_handlers.is_empty() {
1122 while let Some(pos) = extra_handlers.iter().position(|handler| {
1124 p2p_stream
1125 .shared_capabilities()
1126 .ensure_matching_capability(&handler.protocol().cap)
1127 .is_err()
1128 }) {
1129 let handler = extra_handlers.remove(pos);
1130 if handler.on_unsupported_by_peer(
1131 p2p_stream.shared_capabilities(),
1132 direction,
1133 their_hello.id,
1134 ) == OnNotSupported::Disconnect
1135 {
1136 return PendingSessionEvent::Disconnected {
1137 remote_addr,
1138 session_id,
1139 direction,
1140 error: Some(PendingSessionHandshakeError::UnsupportedExtraCapability),
1141 };
1142 }
1143 }
1144 }
1145
1146 let eth_version = match p2p_stream.shared_capabilities().eth_version() {
1148 Ok(version) => version,
1149 Err(err) => {
1150 return PendingSessionEvent::Disconnected {
1151 remote_addr,
1152 session_id,
1153 direction,
1154 error: Some(PendingSessionHandshakeError::Eth(err.into())),
1155 }
1156 }
1157 };
1158
1159 status.set_eth_version(eth_version);
1161
1162 let (conn, their_status) = if p2p_stream.shared_capabilities().len() == 1 {
1163 match handshake
1168 .handshake(&mut p2p_stream, status, fork_filter.clone(), HANDSHAKE_TIMEOUT)
1169 .await
1170 {
1171 Ok(their_status) => {
1172 let eth_stream =
1173 EthStream::with_max_message_size(eth_version, p2p_stream, eth_max_message_size);
1174 (eth_stream.into(), their_status)
1175 }
1176 Err(err) => {
1177 return PendingSessionEvent::Disconnected {
1178 remote_addr,
1179 session_id,
1180 direction,
1181 error: Some(PendingSessionHandshakeError::Eth(err)),
1182 }
1183 }
1184 }
1185 } else if p2p_stream.shared_capabilities().is_exact_eth_snap_v2() {
1186 match EthSnapStream::handshake(
1191 p2p_stream,
1192 status,
1193 fork_filter,
1194 handshake,
1195 eth_max_message_size,
1196 )
1197 .await
1198 {
1199 Ok((stream, their_status)) => (stream.into(), their_status),
1200 Err(err) => {
1201 return PendingSessionEvent::Disconnected {
1202 remote_addr,
1203 session_id,
1204 direction,
1205 error: Some(PendingSessionHandshakeError::Eth(err)),
1206 }
1207 }
1208 }
1209 } else {
1210 let mut multiplex_stream = RlpxProtocolMultiplexer::new(p2p_stream);
1212
1213 for handler in extra_handlers.into_iter() {
1215 let cap = handler.protocol().cap;
1216 let remote_peer_id = their_hello.id;
1217
1218 multiplex_stream
1219 .install_protocol(&cap, move |conn| {
1220 handler.into_connection(direction, remote_peer_id, conn)
1221 })
1222 .ok();
1223 }
1224
1225 let (multiplex_stream, their_status) = match multiplex_stream
1226 .into_eth_satellite_stream(status, fork_filter, handshake, eth_max_message_size)
1227 .await
1228 {
1229 Ok((multiplex_stream, their_status)) => (multiplex_stream, their_status),
1230 Err(err) => {
1231 return PendingSessionEvent::Disconnected {
1232 remote_addr,
1233 session_id,
1234 direction,
1235 error: Some(PendingSessionHandshakeError::Eth(err)),
1236 }
1237 }
1238 };
1239
1240 (multiplex_stream.into(), their_status)
1241 };
1242
1243 let peer_listen_port = (their_hello.port != 0).then_some(their_hello.port);
1245
1246 PendingSessionEvent::Established {
1247 session_id,
1248 remote_addr,
1249 local_addr,
1250 peer_id: their_hello.id,
1251 capabilities: Arc::new(Capabilities::from(their_hello.capabilities)),
1252 status: Arc::new(their_status),
1253 conn,
1254 direction,
1255 client_id: their_hello.client_version,
1256 peer_listen_port,
1257 }
1258}