1use std::{collections::HashMap, convert::Infallible, net::SocketAddr, sync::Arc, time::Duration};
10
11use bytes::Bytes;
12use derive_more::Debug;
13use http::{
14 header::{CONNECTION, SEC_WEBSOCKET_KEY, SEC_WEBSOCKET_PROTOCOL, SEC_WEBSOCKET_VERSION},
15 response::Builder as ResponseBuilder,
16};
17use hyper::{
18 HeaderMap, Method, Request, Response, StatusCode,
19 body::Incoming,
20 header::{HeaderValue, SEC_WEBSOCKET_ACCEPT, UPGRADE},
21 service::Service,
22 upgrade::Upgraded,
23};
24use n0_error::{e, ensure, stack_error};
25use n0_future::MaybeFuture;
26use tokio::{
27 net::{TcpListener, TcpStream},
28 sync::{Notify, watch},
29 time::Instant,
30};
31use tokio_rustls_acme::AcmeAcceptor;
32use tokio_util::{sync::CancellationToken, task::AbortOnDropHandle};
33use tracing::{Instrument, debug, error, info, info_span, trace, warn};
34
35use super::{
36 AllowAll, ClientRequest, DynAccessControl, SpawnError, clients::Clients,
37 streams::InvalidBucketConfig,
38};
39use crate::{
40 KeyCache,
41 defaults::{DEFAULT_KEY_CACHE_CAPACITY, timeouts::SERVER_WRITE_TIMEOUT},
42 http::{
43 CLIENT_AUTH_HEADER, ProtocolVersion, RELAY_PATH, SUPPORTED_WEBSOCKET_VERSION,
44 WEBSOCKET_UPGRADE_PROTOCOL,
45 },
46 protos::{handshake, relay::MAX_FRAME_SIZE, streams::WsBytesFramed},
47 server::{
48 ClientRateLimit,
49 client::Config,
50 metrics::Metrics,
51 streams::{MaybeTlsStream, RateLimited, RelayedStream},
52 },
53};
54
55pub type BytesBody = Box<
57 dyn 'static + Send + Unpin + hyper::body::Body<Data = hyper::body::Bytes, Error = Infallible>,
58>;
59pub type HyperError = Box<dyn std::error::Error + Send + Sync>;
61pub type HyperResult<T> = std::result::Result<T, HyperError>;
63pub(super) type HyperHandler = Box<
64 dyn Fn(Request<Incoming>, ResponseBuilder) -> HyperResult<Response<BytesBody>>
65 + Send
66 + Sync
67 + 'static,
68>;
69
70const SEC_WEBSOCKET_ACCEPT_GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
72
73const ESTABLISH_TIMEOUT: Duration = Duration::from_secs(30);
78
79fn derive_accept_key(client_key: &HeaderValue) -> String {
82 use sha1::Digest;
83
84 let mut sha1 = sha1::Sha1::new();
85 sha1.update(client_key.as_bytes());
86 sha1.update(SEC_WEBSOCKET_ACCEPT_GUID);
87 data_encoding::BASE64.encode(&sha1.finalize())
88}
89
90fn body_full(content: impl Into<hyper::body::Bytes>) -> BytesBody {
92 Box::new(http_body_util::Full::new(content.into()))
93}
94
95#[allow(clippy::result_large_err)]
96fn downcast_upgrade(upgraded: Upgraded) -> Result<(MaybeTlsStream, Bytes), ConnectionHandlerError> {
97 match upgraded.downcast::<hyper_util::rt::TokioIo<MaybeTlsStream>>() {
98 Ok(parts) => Ok((parts.io.into_inner(), parts.read_buf)),
99 Err(_) => Err(e!(ConnectionHandlerError::DowncastUpgrade)),
100 }
101}
102
103#[derive(Debug)]
111pub(super) struct Server {
112 addr: SocketAddr,
113 http_server_task: AbortOnDropHandle<()>,
114 cancel_server_loop: CancellationToken,
115 service: RelayService,
116}
117
118impl Server {
119 pub(super) fn handle(&self) -> ServerHandle {
124 ServerHandle {
125 cancel_token: self.cancel_server_loop.clone(),
126 }
127 }
128
129 pub(super) fn shutdown(&self) {
131 self.cancel_server_loop.cancel();
132 }
133
134 pub(super) fn task_handle(&mut self) -> &mut AbortOnDropHandle<()> {
140 &mut self.http_server_task
141 }
142
143 pub(super) fn addr(&self) -> SocketAddr {
145 self.addr
146 }
147
148 pub(super) fn service(&self) -> &RelayService {
150 &self.service
151 }
152}
153
154#[derive(Debug, Clone)]
158pub(super) struct ServerHandle {
159 cancel_token: CancellationToken,
160}
161
162impl ServerHandle {
163 pub(super) fn shutdown(&self) {
165 self.cancel_token.cancel()
166 }
167}
168
169#[derive(Debug, Clone)]
210pub struct TlsConfig {
211 pub(super) config: Arc<rustls::ServerConfig>,
213 pub(super) acceptor: TlsAcceptor,
215}
216
217impl TlsConfig {
218 pub fn new(config: Arc<rustls::ServerConfig>) -> Self {
257 let acceptor = tokio_rustls::TlsAcceptor::from(config.clone());
258 Self {
259 config,
260 acceptor: TlsAcceptor::Manual(acceptor),
261 }
262 }
263}
264
265#[allow(missing_docs)]
267#[stack_error(derive, add_meta)]
268#[non_exhaustive]
269pub enum ServeConnectionError {
270 #[error("TLS[acme] handshake")]
271 TlsHandshake {
272 #[error(std_err)]
273 source: std::io::Error,
274 },
275 #[error("TLS[acme] serve connection")]
276 ServeConnection {
277 #[error(std_err)]
278 source: hyper::Error,
279 },
280 #[error("TLS[manual] accept")]
281 ManualAccept {
282 #[error(std_err)]
283 source: std::io::Error,
284 },
285 #[error("TLS[acme] accept")]
286 LetsEncryptAccept {
287 #[error(std_err)]
288 source: std::io::Error,
289 },
290 #[error("HTTPS connection")]
291 Https {
292 #[error(std_err)]
293 source: hyper::Error,
294 },
295 #[error("HTTP connection")]
296 Http {
297 #[error(std_err)]
298 source: hyper::Error,
299 },
300 #[error("Connection did not reach established state within timeout")]
301 EstablishTimeout,
302}
303
304#[allow(missing_docs)]
306#[stack_error(derive, add_meta, from_sources)]
307#[non_exhaustive]
308pub enum AcceptError {
309 #[error(transparent)]
310 Handshake { source: handshake::Error },
311 #[error("rate limiting misconfigured")]
312 RateLimitingMisconfigured { source: InvalidBucketConfig },
313}
314
315#[allow(missing_docs)]
317#[stack_error(derive, add_meta, from_sources)]
318#[non_exhaustive]
319pub enum ConnectionHandlerError {
320 #[error(transparent)]
321 Accept { source: AcceptError },
322 #[error("Could not downcast the upgraded connection to MaybeTlsStream")]
323 DowncastUpgrade {},
324 #[error("Cannot deal with buffered data yet: {buf:?}")]
325 BufferNotEmpty { buf: Bytes },
326}
327
328#[derive(derive_more::Debug)]
333pub(super) struct ServerBuilder {
334 addr: SocketAddr,
336 tls_config: Option<TlsConfig>,
340 handlers: Handlers,
345 headers: HeaderMap,
347 client_rx_ratelimit: Option<ClientRateLimit>,
352 key_cache_capacity: usize,
354 access: Arc<dyn DynAccessControl>,
356 metrics: Option<Arc<Metrics>>,
357 establish_timeout: Duration,
358}
359
360impl ServerBuilder {
361 pub(super) fn new(addr: SocketAddr) -> Self {
363 Self {
364 addr,
365 tls_config: None,
366 handlers: Default::default(),
367 headers: HeaderMap::new(),
368 client_rx_ratelimit: None,
369 key_cache_capacity: DEFAULT_KEY_CACHE_CAPACITY,
370 access: Arc::new(AllowAll),
371 metrics: None,
372 establish_timeout: ESTABLISH_TIMEOUT,
373 }
374 }
375
376 pub(super) fn metrics(mut self, metrics: Arc<Metrics>) -> Self {
378 self.metrics = Some(metrics);
379 self
380 }
381
382 pub(super) fn access(mut self, access: Arc<dyn DynAccessControl>) -> Self {
384 self.access = access;
385 self
386 }
387
388 pub(super) fn tls_config(mut self, config: Option<TlsConfig>) -> Self {
390 self.tls_config = config;
391 self
392 }
393
394 #[cfg(test)]
403 pub(super) fn establish_timeout(mut self, timeout: Duration) -> Self {
404 self.establish_timeout = timeout;
405 self
406 }
407
408 pub(super) fn client_rx_ratelimit(mut self, config: ClientRateLimit) -> Self {
413 self.client_rx_ratelimit = Some(config);
414 self
415 }
416
417 pub(super) fn request_handler(
419 mut self,
420 method: Method,
421 uri_path: &'static str,
422 handler: HyperHandler,
423 ) -> Self {
424 self.handlers.insert((method, uri_path), handler);
425 self
426 }
427
428 pub(super) fn headers(mut self, headers: HeaderMap) -> Self {
430 for (k, v) in headers.iter() {
431 self.headers.insert(k.clone(), v.clone());
432 }
433 self
434 }
435
436 pub(super) fn key_cache_capacity(mut self, capacity: usize) -> Self {
438 self.key_cache_capacity = capacity;
439 self
440 }
441
442 pub(super) async fn spawn(self) -> Result<Server, SpawnError> {
444 let cancel_token = CancellationToken::new();
445
446 let service = RelayService::new(
447 self.handlers,
448 self.headers,
449 self.client_rx_ratelimit,
450 KeyCache::new(self.key_cache_capacity),
451 self.access,
452 self.metrics.unwrap_or_default(),
453 );
454
455 let addr = self.addr;
456 let tls_config = self.tls_config;
457
458 let listener = TcpListener::bind(&addr)
461 .await
462 .map_err(|err| e!(super::SpawnError::BindTcpListener { addr }, err))?;
463
464 let addr = listener
465 .local_addr()
466 .map_err(|err| e!(super::SpawnError::NoLocalAddr, err))?;
467 let http_str = tls_config.as_ref().map_or("HTTP/WS", |_| "HTTPS/WSS");
468 info!("[{http_str}] relay: serving on {addr}");
469
470 let cancel = cancel_token.clone();
471 let loop_service = service.clone();
472 let task = tokio::task::spawn(
473 async move {
474 let service = loop_service;
475 let mut set = tokio::task::JoinSet::new();
477 loop {
478 tokio::select! {
479 biased;
480 _ = cancel.cancelled() => {
481 break;
482 }
483 Some(res) = set.join_next() => {
484 if let Err(err) = res
485 && err.is_panic()
486 {
487 panic!("task panicked: {err:#?}");
488 }
489 }
490 res = listener.accept() => match res {
491 Ok((stream, peer_addr)) => {
492 debug!("connection opened from {peer_addr}");
493 let tls_config = tls_config.clone();
494 let service = service.clone();
495 set.spawn(async move {
497 service
498 .handle_connection(stream, tls_config, self.establish_timeout)
499 .await
500 }.instrument(info_span!("conn", peer = %peer_addr)));
501 }
502 Err(err) => {
503 error!("failed to accept connection: {err}");
504 }
505 }
506 }
507 }
508 service.shutdown().await;
509 set.shutdown().await;
510 debug!("server has been shutdown.");
511 }
512 .instrument(info_span!("relay-http-serve")),
513 );
514
515 Ok(Server {
516 addr,
517 http_server_task: AbortOnDropHandle::new(task),
518 cancel_server_loop: cancel_token,
519 service,
520 })
521 }
522}
523
524#[derive(Clone, Debug)]
528pub struct RelayService(Arc<Inner>);
529
530#[derive(Debug)]
531struct Inner {
532 handlers: Handlers,
533 headers: HeaderMap,
534 clients: Clients,
535 write_timeout: Duration,
536 rate_limit: watch::Sender<Option<ClientRateLimit>>,
537 key_cache: KeyCache,
538 access: Arc<dyn DynAccessControl>,
539 metrics: Arc<Metrics>,
540}
541
542#[stack_error(derive, add_meta)]
543enum RelayUpgradeReqError {
544 #[error("missing header: {header}")]
545 MissingHeader { header: http::HeaderName },
546 #[error("invalid header value for {header}: {details}")]
547 InvalidHeader {
548 header: http::HeaderName,
549 details: String,
550 },
551 #[error(
552 "invalid header value for {SEC_WEBSOCKET_VERSION}: unsupported websocket version, only supporting {SUPPORTED_WEBSOCKET_VERSION}"
553 )]
554 UnsupportedWebsocketVersion,
555 #[error(
556 "invalid header value for {SEC_WEBSOCKET_PROTOCOL}: unsupported relay version: we support {we_support} but you only provide {you_support}"
557 )]
558 UnsupportedRelayVersion {
559 we_support: String,
560 you_support: String,
561 },
562}
563
564impl RelayServiceWithNotify {
565 fn build_response(&self) -> http::response::Builder {
566 let mut res = Response::builder();
567 for (key, value) in self.service.0.headers.iter() {
568 res = res.header(key, value);
569 }
570 res
571 }
572
573 fn handle_relay_ws_upgrade(
575 &self,
576 mut req: Request<Incoming>,
577 ) -> Result<Response<BytesBody>, RelayUpgradeReqError> {
578 fn expect_header(
579 req: &Request<Incoming>,
580 header: http::HeaderName,
581 ) -> Result<&HeaderValue, RelayUpgradeReqError> {
582 req.headers()
583 .get(&header)
584 .ok_or_else(|| e!(RelayUpgradeReqError::MissingHeader { header }))
585 }
586
587 let upgrade_header = expect_header(&req, UPGRADE)?;
588 ensure!(
589 upgrade_header == HeaderValue::from_static(WEBSOCKET_UPGRADE_PROTOCOL),
590 RelayUpgradeReqError::InvalidHeader {
591 header: UPGRADE,
592 details: format!("value must be {WEBSOCKET_UPGRADE_PROTOCOL}")
593 }
594 );
595
596 let key = expect_header(&req, SEC_WEBSOCKET_KEY)?.clone();
597 let version = expect_header(&req, SEC_WEBSOCKET_VERSION)?.clone();
598
599 ensure!(
600 version.as_bytes() == SUPPORTED_WEBSOCKET_VERSION.as_bytes(),
601 RelayUpgradeReqError::UnsupportedWebsocketVersion
602 );
603
604 let subprotocols = expect_header(&req, SEC_WEBSOCKET_PROTOCOL)?
605 .to_str()
606 .ok()
607 .ok_or_else(|| {
608 e!(RelayUpgradeReqError::InvalidHeader {
609 header: SEC_WEBSOCKET_PROTOCOL,
610 details: "header value is not ascii".to_string()
611 })
612 })?;
613 let protocol_version = subprotocols
614 .split(",")
615 .map(|s| s.trim())
616 .filter_map(ProtocolVersion::match_from_str)
617 .max()
618 .ok_or_else(|| {
619 e!(RelayUpgradeReqError::UnsupportedRelayVersion {
620 we_support: ProtocolVersion::all_joined(),
621 you_support: subprotocols.to_string()
622 })
623 })?;
624
625 tokio::task::spawn({
633 let this = self.clone();
634 let deadline = Instant::now() + this.establish_timeout;
635 let establish = async move {
636 match hyper::upgrade::on(&mut req).await {
637 Ok(upgraded) => {
638 let (parts, _) = req.into_parts();
639 if let Err(err) = this
640 .service
641 .0
642 .relay_connection_handler(upgraded, parts, protocol_version)
643 .await
644 {
645 warn!("error accepting upgraded connection: {err:#}",);
646 } else {
647 this.on_establish.notify_waiters();
651 debug!("upgraded connection completed");
652 };
653 }
654 Err(err) => warn!("upgrade error: {err:#}"),
655 }
656 };
657 async move {
658 if tokio::time::timeout_at(deadline, establish).await.is_err() {
661 debug!("relay connection establishment timed out");
662 }
663 }
664 .instrument(info_span!("handler"))
665 });
666
667 Ok(self
670 .build_response()
671 .status(StatusCode::SWITCHING_PROTOCOLS)
672 .header(
673 UPGRADE,
674 HeaderValue::from_static(WEBSOCKET_UPGRADE_PROTOCOL),
675 )
676 .header(SEC_WEBSOCKET_ACCEPT, derive_accept_key(&key))
677 .header(SEC_WEBSOCKET_PROTOCOL, protocol_version.to_header_value())
678 .header(CONNECTION, "upgrade")
679 .body(body_full("switching to websocket protocol"))
680 .expect("valid body"))
681 }
682}
683
684#[derive(Debug, Clone)]
737pub struct RelayServiceWithNotify {
738 service: RelayService,
739 on_establish: Arc<Notify>,
740 establish_timeout: Duration,
741}
742
743impl RelayServiceWithNotify {
744 pub fn new(service: RelayService, on_establish: Arc<Notify>) -> Self {
751 Self::with_timeout(service, on_establish, ESTABLISH_TIMEOUT)
752 }
753
754 pub fn with_timeout(
763 service: RelayService,
764 on_establish: Arc<Notify>,
765 timeout: Duration,
766 ) -> Self {
767 Self {
768 service,
769 on_establish,
770 establish_timeout: timeout,
771 }
772 }
773}
774
775impl Service<Request<Incoming>> for RelayServiceWithNotify {
776 type Response = Response<BytesBody>;
777 type Error = HyperError;
778 type Future = std::future::Ready<Result<Self::Response, Self::Error>>;
779
780 fn call(&self, req: Request<Incoming>) -> Self::Future {
781 if matches!(
783 (req.method(), req.uri().path()),
784 (&hyper::Method::GET, RELAY_PATH)
785 ) {
786 let response = match self.handle_relay_ws_upgrade(req) {
787 Ok(response) => Ok(response),
788 Err(e @ RelayUpgradeReqError::UnsupportedWebsocketVersion { .. }) => self
790 .build_response()
791 .status(StatusCode::BAD_REQUEST)
792 .header(SEC_WEBSOCKET_VERSION, SUPPORTED_WEBSOCKET_VERSION)
793 .body(body_full(e.to_string())),
794 Err(e) => self
795 .build_response()
796 .status(StatusCode::BAD_REQUEST)
797 .body(body_full(e.to_string())),
798 }
799 .map_err(Into::into);
800 return std::future::ready(response);
801 }
802 let uri = req.uri().clone();
806 if let Some(handler) = self
807 .service
808 .0
809 .handlers
810 .get(&(req.method().clone(), uri.path()))
811 {
812 let response = handler(req, self.service.0.default_response());
813 return std::future::ready(response);
814 }
815
816 let response = self
818 .service
819 .0
820 .not_found_fn(req, self.service.0.default_response());
821 std::future::ready(response)
822 }
823}
824
825impl Inner {
826 fn default_response(&self) -> ResponseBuilder {
827 let mut response = Response::builder();
828 for (key, value) in self.headers.iter() {
829 response = response.header(key.clone(), value.clone());
830 }
831 response
832 }
833
834 fn not_found_fn(
835 &self,
836 _req: Request<Incoming>,
837 mut res: ResponseBuilder,
838 ) -> HyperResult<Response<BytesBody>> {
839 for (k, v) in self.headers.iter() {
840 res = res.header(k.clone(), v.clone());
841 }
842 let body = body_full("Not Found");
843 let r = res.status(StatusCode::NOT_FOUND).body(body)?;
844 HyperResult::Ok(r)
845 }
846
847 async fn relay_connection_handler(
853 &self,
854 upgraded: Upgraded,
855 request_parts: http::request::Parts,
856 protocol_version: ProtocolVersion,
857 ) -> Result<(), ConnectionHandlerError> {
858 debug!("relay_connection upgraded");
859 let (io, read_buf) = downcast_upgrade(upgraded)?;
860 if !read_buf.is_empty() {
861 return Err(e!(ConnectionHandlerError::BufferNotEmpty { buf: read_buf }));
862 }
863
864 self.accept(io, request_parts, protocol_version).await?;
865 Ok(())
866 }
867
868 async fn accept(
879 &self,
880 io: MaybeTlsStream,
881 request_parts: http::request::Parts,
882 protocol_version: ProtocolVersion,
883 ) -> Result<(), AcceptError> {
884 trace!("accept: start");
885
886 io.disable_nagle();
888
889 let io = RateLimited::from_watcher(io, self.rate_limit.subscribe(), self.metrics.clone())
890 .map_err(|err| e!(AcceptError::RateLimitingMisconfigured, err))?;
891 let limited_watcher = io.limited_watcher();
892
893 let websocket = tokio_websockets::ServerBuilder::new()
895 .limits(tokio_websockets::Limits::default().max_payload_len(Some(MAX_FRAME_SIZE)))
896 .serve(io);
898
899 let mut io = WsBytesFramed { io: websocket };
900
901 let client_auth_header = request_parts.headers.get(CLIENT_AUTH_HEADER).cloned();
902 let authentication = handshake::serverside(&mut io, client_auth_header).await?;
903
904 trace!(?authentication.mechanism, "accept: verified authentication");
905
906 let request =
907 ClientRequest::new(authentication.client_key, protocol_version, request_parts);
908
909 let guard = authentication
911 .authorize_with(&request, &self.access, &mut io)
912 .await?;
913
914 trace!("accept: verified authorization");
915
916 let io = RelayedStream {
917 inner: io,
918 key_cache: self.key_cache.clone(),
919 };
920
921 trace!("accept: build client conn");
922 let mut client_conn_builder = Config::new(guard, io, protocol_version);
923 client_conn_builder.write_timeout = self.write_timeout;
924 client_conn_builder.rate_limited = Some(limited_watcher);
925 trace!(endpoint_id = %request.endpoint_id().fmt_short(), "create client");
926
927 self.clients
930 .register(client_conn_builder, self.metrics.clone());
931 Ok(())
932 }
933}
934
935#[derive(Clone, derive_more::Debug)]
937pub(super) enum TlsAcceptor {
938 LetsEncrypt(#[debug("tokio_rustls_acme::AcmeAcceptor")] AcmeAcceptor),
940 Manual(#[debug("tokio_rustls::TlsAcceptor")] tokio_rustls::TlsAcceptor),
943}
944
945impl RelayService {
946 pub fn new(
950 handlers: Handlers,
951 headers: HeaderMap,
952 rate_limit: Option<ClientRateLimit>,
953 key_cache: KeyCache,
954 access: Arc<dyn DynAccessControl>,
955 metrics: Arc<Metrics>,
956 ) -> Self {
957 Self(Arc::new(Inner {
958 handlers,
959 headers,
960 clients: Clients::default(),
961 write_timeout: SERVER_WRITE_TIMEOUT,
962 rate_limit: watch::Sender::new(rate_limit),
963 key_cache,
964 access,
965 metrics,
966 }))
967 }
968
969 pub fn set_client_rate_limit(&self, rate_limit: Option<ClientRateLimit>) {
974 self.0.rate_limit.send_replace(rate_limit);
975 }
976
977 pub async fn shutdown(&self) {
979 self.0.clients.shutdown().await;
980 }
981
982 pub fn clients(&self) -> &Clients {
987 &self.0.clients
988 }
989
990 pub async fn handle_connection(
1050 self,
1051 stream: TcpStream,
1052 tls_config: Option<TlsConfig>,
1053 establish_timeout: Duration,
1054 ) {
1055 let metrics = self.0.metrics.clone();
1056 metrics.http_connections.inc();
1057 let on_establish = Arc::new(Notify::new());
1060 let service =
1061 RelayServiceWithNotify::with_timeout(self, on_establish.clone(), establish_timeout);
1062
1063 let serve_fut = async move {
1065 match tls_config {
1066 Some(tls_config) => {
1067 debug!("HTTPS: serve connection");
1068 service.tls_serve_connection(stream, tls_config).await
1069 }
1070 None => {
1071 debug!("HTTP: serve connection");
1072 let stream = MaybeTlsStream::Plain(stream);
1073 service.serve_connection(stream).await
1074 }
1075 }
1076 };
1077
1078 let res = clearable_timeout(establish_timeout, on_establish, serve_fut)
1081 .await
1082 .map_err(|_elapsed| e!(ServeConnectionError::EstablishTimeout))
1083 .flatten();
1084
1085 metrics.http_connections_closed.inc();
1086
1087 if let Err(error) = res {
1088 match error {
1089 ServeConnectionError::ManualAccept { source, .. }
1090 | ServeConnectionError::LetsEncryptAccept { source, .. }
1091 if source.kind() == std::io::ErrorKind::UnexpectedEof =>
1092 {
1093 debug!(reason=?source, "peer disconnected");
1094 }
1095 ServeConnectionError::Https { source, .. }
1098 | ServeConnectionError::Http { source, .. }
1099 if source.is_incomplete_message() =>
1100 {
1101 debug!(reason=?source, "peer disconnected");
1102 }
1103 _ => {
1104 metrics.http_connections_errored.inc();
1105 error!(?error, "failed to handle connection");
1106 }
1107 }
1108 }
1109 }
1110}
1111
1112impl RelayServiceWithNotify {
1113 async fn tls_serve_connection(
1115 self,
1116 stream: TcpStream,
1117 tls_config: TlsConfig,
1118 ) -> Result<(), ServeConnectionError> {
1119 let TlsConfig { acceptor, config } = tls_config;
1120 let stream = match acceptor {
1121 TlsAcceptor::LetsEncrypt(a) => {
1122 match a
1123 .accept(stream)
1124 .await
1125 .map_err(|err| e!(ServeConnectionError::LetsEncryptAccept, err))?
1126 {
1127 None => {
1128 info!("TLS[acme]: received TLS-ALPN-01 validation request");
1129 return Ok(());
1130 }
1131 Some(start_handshake) => {
1132 debug!("TLS[acme]: start handshake");
1133 let tls_stream = start_handshake
1134 .into_stream(config)
1135 .await
1136 .map_err(|err| e!(ServeConnectionError::TlsHandshake, err))?;
1137 MaybeTlsStream::Tls(tls_stream)
1138 }
1139 }
1140 }
1141 TlsAcceptor::Manual(a) => {
1142 debug!("TLS[manual]: accept");
1143 let tls_stream = a
1144 .accept(stream)
1145 .await
1146 .map_err(|err| e!(ServeConnectionError::ManualAccept, err))?;
1147 MaybeTlsStream::Tls(tls_stream)
1148 }
1149 };
1150 self.serve_connection(stream).await
1151 }
1152
1153 async fn serve_connection(self, io: MaybeTlsStream) -> Result<(), ServeConnectionError> {
1155 hyper::server::conn::http1::Builder::new()
1156 .serve_connection(hyper_util::rt::TokioIo::new(io), self)
1157 .with_upgrades()
1158 .await
1159 .map_err(|err| e!(ServeConnectionError::ServeConnection, err))
1160 }
1161}
1162
1163#[derive(Default)]
1165pub struct Handlers(HashMap<(Method, &'static str), HyperHandler>);
1166
1167impl std::fmt::Debug for Handlers {
1168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1169 let s = self.0.keys().fold(String::new(), |curr, next| {
1170 let (method, uri) = next;
1171 format!("{curr}\n({method},{uri}): Box<Fn(ResponseBuilder) -> Result<Response<Body>> + Send + Sync + 'static>")
1172 });
1173 write!(f, "HashMap<{s}>")
1174 }
1175}
1176
1177impl std::ops::Deref for Handlers {
1178 type Target = HashMap<(Method, &'static str), HyperHandler>;
1179
1180 fn deref(&self) -> &Self::Target {
1181 &self.0
1182 }
1183}
1184
1185impl std::ops::DerefMut for Handlers {
1186 fn deref_mut(&mut self) -> &mut Self::Target {
1187 &mut self.0
1188 }
1189}
1190
1191async fn clearable_timeout<F: Future>(
1198 timeout: Duration,
1199 clear_timeout: Arc<Notify>,
1200 fut: F,
1201) -> Result<F::Output, Elapsed> {
1202 tokio::pin!(fut);
1203 let timeout = MaybeFuture::Some(tokio::time::sleep(timeout));
1204 tokio::pin!(timeout);
1205 loop {
1206 tokio::select! {
1207 biased;
1208 res = &mut fut => {
1209 return Ok(res);
1210 }
1211 _ = clear_timeout.notified() => {
1212 timeout.as_mut().set_none();
1213 },
1214 _ = &mut timeout => {
1215 return Err(Elapsed);
1216 }
1217 }
1218 }
1219}
1220
1221#[stack_error(derive)]
1222#[error("Timeout elapsed")]
1223struct Elapsed;
1224
1225#[cfg(test)]
1226mod tests {
1227 use std::sync::Arc;
1228
1229 use iroh_base::{PublicKey, SecretKey};
1230 use iroh_dns::dns::DnsResolver;
1231 use n0_error::{Result, StdResultExt, bail_any};
1232 use n0_future::{SinkExt, StreamExt};
1233 use n0_tracing_test::traced_test;
1234 use rand::{RngExt, SeedableRng};
1235 use reqwest::Url;
1236 use tokio::io::{AsyncReadExt, AsyncWriteExt};
1237 use tracing::info;
1238
1239 use super::*;
1240 use crate::{
1241 client::{Client, ClientBuilder, ConnectError, conn::Conn},
1242 protos::relay::{ClientToRelayMsg, Datagrams, RelayToClientMsg},
1243 tls::{CaTlsConfig, default_provider},
1244 };
1245
1246 pub(crate) fn make_tls_config() -> TlsConfig {
1247 let subject_alt_names = vec!["localhost".to_string()];
1248
1249 let cert = rcgen::generate_simple_self_signed(subject_alt_names).unwrap();
1250 let rustls_certificate = cert.cert.der().clone();
1251 let rustls_key =
1252 rustls::pki_types::PrivatePkcs8KeyDer::from(cert.signing_key.serialize_der());
1253 let config = rustls::ServerConfig::builder_with_provider(Arc::new(
1254 rustls::crypto::ring::default_provider(),
1255 ))
1256 .with_safe_default_protocol_versions()
1257 .expect("protocols supported by ring")
1258 .with_no_client_auth()
1259 .with_single_cert(vec![(rustls_certificate)], rustls_key.into())
1260 .expect("cert is right");
1261
1262 TlsConfig::new(Arc::new(config))
1263 }
1264
1265 #[tokio::test]
1266 #[traced_test]
1267 async fn test_http_clients_and_server() -> Result {
1268 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0u64);
1269
1270 let a_key = SecretKey::from_bytes(&rng.random());
1271 let b_key = SecretKey::from_bytes(&rng.random());
1272
1273 let server = ServerBuilder::new("127.0.0.1:0".parse().unwrap())
1275 .spawn()
1276 .await?;
1277
1278 let addr = server.addr();
1279
1280 let port = addr.port();
1282 let addr = if let std::net::IpAddr::V4(ipv4_addr) = addr.ip() {
1283 ipv4_addr
1284 } else {
1285 bail_any!("cannot get ipv4 addr from socket addr {addr:?}");
1286 };
1287
1288 info!("addr: {addr}:{port}");
1289 let relay_addr: Url = format!("http://{addr}:{port}").parse().unwrap();
1290
1291 let (a_key, mut client_a) = create_test_client(a_key, relay_addr.clone()).await?;
1293 info!("created client {a_key:?}");
1294 let (b_key, mut client_b) = create_test_client(b_key, relay_addr).await?;
1295 info!("created client {b_key:?}");
1296
1297 info!("ping a");
1298 client_a.send(ClientToRelayMsg::Ping([1u8; 8])).await?;
1299 let pong = client_a.next().await.expect("eos")?;
1300 assert!(matches!(pong, RelayToClientMsg::Pong { .. }));
1301
1302 info!("ping b");
1303 client_b.send(ClientToRelayMsg::Ping([2u8; 8])).await?;
1304 let pong = client_b.next().await.expect("eos")?;
1305 assert!(matches!(pong, RelayToClientMsg::Pong { .. }));
1306
1307 info!("sending message from a to b");
1308 let msg = Datagrams::from(b"hi there, client b!");
1309 client_a
1310 .send(ClientToRelayMsg::Datagrams {
1311 dst_endpoint_id: b_key,
1312 datagrams: msg.clone(),
1313 })
1314 .await?;
1315 info!("waiting for message from a on b");
1316 let (got_key, got_msg) =
1317 process_msg(client_b.next().await).expect("expected message from client_a");
1318 assert_eq!(a_key, got_key);
1319 assert_eq!(msg, got_msg);
1320
1321 info!("sending message from b to a");
1322 let msg = Datagrams::from(b"right back at ya, client b!");
1323 client_b
1324 .send(ClientToRelayMsg::Datagrams {
1325 dst_endpoint_id: a_key,
1326 datagrams: msg.clone(),
1327 })
1328 .await?;
1329 info!("waiting for message b on a");
1330 let (got_key, got_msg) =
1331 process_msg(client_a.next().await).expect("expected message from client_b");
1332 assert_eq!(b_key, got_key);
1333 assert_eq!(msg, got_msg);
1334
1335 client_a.close().await?;
1337 client_b.close().await?;
1338 server.shutdown();
1339
1340 Ok(())
1341 }
1342
1343 async fn create_test_client(
1344 key: SecretKey,
1345 server_url: Url,
1346 ) -> Result<(PublicKey, Client), ConnectError> {
1347 let public_key = key.public();
1348 let client = ClientBuilder::new(server_url, key, DnsResolver::new()).tls_client_config(
1349 CaTlsConfig::insecure_skip_verify()
1350 .client_config(default_provider())
1351 .expect("infallible"),
1352 );
1353 let client = client.connect().await?;
1354
1355 Ok((public_key, client))
1356 }
1357
1358 fn process_msg(
1359 msg: Option<Result<RelayToClientMsg, crate::client::RecvError>>,
1360 ) -> Option<(PublicKey, Datagrams)> {
1361 match msg {
1362 Some(Err(e)) => {
1363 info!("client `recv` error {e}");
1364 None
1365 }
1366 Some(Ok(msg)) => {
1367 info!("got message on: {msg:?}");
1368 if let RelayToClientMsg::Datagrams {
1369 remote_endpoint_id: source,
1370 datagrams,
1371 } = msg
1372 {
1373 Some((source, datagrams))
1374 } else {
1375 None
1376 }
1377 }
1378 None => {
1379 info!("client end of stream");
1380 None
1381 }
1382 }
1383 }
1384
1385 #[tokio::test]
1386 #[traced_test]
1387 async fn test_subprotocol_negotiation_picks_latest() -> Result {
1388 let server = ServerBuilder::new("127.0.0.1:0".parse().unwrap())
1389 .spawn()
1390 .await?;
1391 let addr = server.addr();
1392
1393 for offered in [
1394 "iroh-relay-v2,iroh-relay-v1",
1395 "iroh-relay-v1,iroh-relay-v2",
1396 "baz, iroh-relay-v1, iroh-relay-v2, boo",
1397 "foo, iroh-relay-v2, bar",
1398 ] {
1399 let ws_uri = format!("ws://{addr}{RELAY_PATH}");
1400 let (_stream, response) = tokio_websockets::ClientBuilder::new()
1401 .uri(&ws_uri)
1402 .expect("valid websocket URI")
1403 .add_header(
1404 SEC_WEBSOCKET_PROTOCOL,
1405 HeaderValue::from_str(offered).expect("valid subprotocol header value"),
1406 )
1407 .expect("header accepted by websocket client")
1408 .connect()
1409 .await
1410 .expect("websocket upgrade succeeds");
1411 let negotiated = response
1412 .headers()
1413 .get(SEC_WEBSOCKET_PROTOCOL)
1414 .expect("Sec-WebSocket-Protocol response header is present");
1415 assert_eq!(negotiated, "iroh-relay-v2", "offered={offered}");
1416 }
1417
1418 server.shutdown();
1419 Ok(())
1420 }
1421
1422 #[tokio::test]
1423 #[traced_test]
1424 async fn test_https_clients_and_server() -> Result {
1425 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0u64);
1426
1427 let a_key = SecretKey::from_bytes(&rng.random());
1428 let b_key = SecretKey::from_bytes(&rng.random());
1429
1430 let tls_config = make_tls_config();
1432
1433 let mut server = ServerBuilder::new("127.0.0.1:0".parse().unwrap())
1435 .tls_config(Some(tls_config))
1436 .spawn()
1437 .await?;
1438
1439 let addr = server.addr();
1440
1441 let port = addr.port();
1443 let addr = if let std::net::IpAddr::V4(ipv4_addr) = addr.ip() {
1444 ipv4_addr
1445 } else {
1446 bail_any!("cannot get ipv4 addr from socket addr {addr:?}");
1447 };
1448
1449 info!("Relay listening on: {addr}:{port}");
1450
1451 let url: Url = format!("https://localhost:{port}").parse().unwrap();
1452
1453 let (a_key, mut client_a) = create_test_client(a_key, url.clone()).await?;
1455 info!("created client {a_key:?}");
1456 let (b_key, mut client_b) = create_test_client(b_key, url).await?;
1457 info!("created client {b_key:?}");
1458
1459 info!("ping a");
1460 client_a.send(ClientToRelayMsg::Ping([1u8; 8])).await?;
1461 let pong = client_a.next().await.expect("eos")?;
1462 assert!(matches!(pong, RelayToClientMsg::Pong { .. }));
1463
1464 info!("ping b");
1465 client_b.send(ClientToRelayMsg::Ping([2u8; 8])).await?;
1466 let pong = client_b.next().await.expect("eos")?;
1467 assert!(matches!(pong, RelayToClientMsg::Pong { .. }));
1468
1469 info!("sending message from a to b");
1470 let msg = Datagrams::from(b"hi there, client b!");
1471 client_a
1472 .send(ClientToRelayMsg::Datagrams {
1473 dst_endpoint_id: b_key,
1474 datagrams: msg.clone(),
1475 })
1476 .await?;
1477 info!("waiting for message from a on b");
1478 let (got_key, got_msg) =
1479 process_msg(client_b.next().await).expect("expected message from client_a");
1480 assert_eq!(a_key, got_key);
1481 assert_eq!(msg, got_msg);
1482
1483 info!("sending message from b to a");
1484 let msg = Datagrams::from(b"right back at ya, client b!");
1485 client_b
1486 .send(ClientToRelayMsg::Datagrams {
1487 dst_endpoint_id: a_key,
1488 datagrams: msg.clone(),
1489 })
1490 .await?;
1491 info!("waiting for message b on a");
1492 let (got_key, got_msg) =
1493 process_msg(client_a.next().await).expect("expected message from client_b");
1494 assert_eq!(b_key, got_key);
1495 assert_eq!(msg, got_msg);
1496
1497 client_a.close().await?;
1499 client_b.close().await?;
1500 server.shutdown();
1501 server.task_handle().await.std_context("join")?;
1502
1503 Ok(())
1504 }
1505
1506 async fn make_test_client(client: tokio::io::DuplexStream, key: &SecretKey) -> Result<Conn> {
1507 let client = crate::client::streams::MaybeTlsStream::Test(client);
1508 let client = tokio_websockets::ClientBuilder::new().take_over(client);
1509 let client = Conn::new(client, KeyCache::test(), key, Default::default()).await?;
1510 Ok(client)
1511 }
1512
1513 #[tokio::test]
1514 #[traced_test]
1515 async fn test_server_basic() -> Result {
1516 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0u64);
1517
1518 info!("Create the server.");
1519 let metrics = Arc::new(Metrics::default());
1520 let service = RelayService::new(
1521 Default::default(),
1522 Default::default(),
1523 None,
1524 KeyCache::test(),
1525 Arc::new(crate::server::AllowAll),
1526 metrics.clone(),
1527 );
1528
1529 info!("Create client A and connect it to the server.");
1530 let key_a = SecretKey::from_bytes(&rng.random());
1531 let public_key_a = key_a.public();
1532 let (client_a, rw_a) = tokio::io::duplex(10);
1533 let s = service.clone();
1534 let handler_task = tokio::spawn(async move {
1535 s.0.accept(
1536 MaybeTlsStream::Test(rw_a),
1537 Request::new(()).into_parts().0,
1538 Default::default(),
1539 )
1540 .await
1541 });
1542 let mut client_a = make_test_client(client_a, &key_a).await?;
1543 handler_task.await.std_context("join")??;
1544
1545 info!("Create client B and connect it to the server.");
1546 let key_b = SecretKey::from_bytes(&rng.random());
1547 let public_key_b = key_b.public();
1548 let (client_b, rw_b) = tokio::io::duplex(10);
1549 let s = service.clone();
1550 let handler_task = tokio::spawn(async move {
1551 s.0.accept(
1552 MaybeTlsStream::Test(rw_b),
1553 Request::new(()).into_parts().0,
1554 Default::default(),
1555 )
1556 .await
1557 });
1558 let mut client_b = make_test_client(client_b, &key_b).await?;
1559 handler_task.await.std_context("join")??;
1560
1561 info!("Send message from A to B.");
1562 let msg = Datagrams::from(b"hello client b!!");
1563 client_a
1564 .send(ClientToRelayMsg::Datagrams {
1565 dst_endpoint_id: public_key_b,
1566 datagrams: msg.clone(),
1567 })
1568 .await?;
1569 match client_b.next().await.unwrap()? {
1570 RelayToClientMsg::Datagrams {
1571 remote_endpoint_id,
1572 datagrams,
1573 } => {
1574 assert_eq!(public_key_a, remote_endpoint_id);
1575 assert_eq!(msg, datagrams);
1576 }
1577 msg => {
1578 bail_any!("expected ReceivedDatagrams msg, got {msg:?}");
1579 }
1580 }
1581
1582 info!("Send message from B to A.");
1583 let msg = Datagrams::from(b"nice to meet you client a!!");
1584 client_b
1585 .send(ClientToRelayMsg::Datagrams {
1586 dst_endpoint_id: public_key_a,
1587 datagrams: msg.clone(),
1588 })
1589 .await?;
1590 match client_a.next().await.unwrap()? {
1591 RelayToClientMsg::Datagrams {
1592 remote_endpoint_id,
1593 datagrams,
1594 } => {
1595 assert_eq!(public_key_b, remote_endpoint_id);
1596 assert_eq!(msg, datagrams);
1597 }
1598 msg => {
1599 bail_any!("expected ReceivedDatagrams msg, got {msg:?}");
1600 }
1601 }
1602
1603 info!("Close the server and clients");
1604 service.shutdown().await;
1605 tokio::time::sleep(Duration::from_secs(1)).await;
1606
1607 info!("Fail to send message from A to B.");
1608 let res = client_a
1609 .send(ClientToRelayMsg::Datagrams {
1610 dst_endpoint_id: public_key_b,
1611 datagrams: Datagrams::from(b"try to send"),
1612 })
1613 .await;
1614 assert!(res.is_err());
1615 assert!(client_b.next().await.is_none());
1616
1617 drop(client_a);
1618 drop(client_b);
1619
1620 service.shutdown().await;
1621
1622 assert_eq!(metrics.accepts.get(), metrics.disconnects.get());
1623
1624 Ok(())
1625 }
1626
1627 #[tokio::test]
1628 async fn test_server_replace_client() -> Result {
1629 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0u64);
1630
1631 info!("Create the server.");
1632 let service = RelayService::new(
1633 Default::default(),
1634 Default::default(),
1635 None,
1636 KeyCache::test(),
1637 Arc::new(crate::server::AllowAll),
1638 Default::default(),
1639 );
1640
1641 info!("Create client A and connect it to the server.");
1642 let key_a = SecretKey::from_bytes(&rng.random());
1643 let public_key_a = key_a.public();
1644 let (client_a, rw_a) = tokio::io::duplex(10);
1645 let s = service.clone();
1646 let handler_task = tokio::spawn(async move {
1647 s.0.accept(
1648 MaybeTlsStream::Test(rw_a),
1649 Request::new(()).into_parts().0,
1650 Default::default(),
1651 )
1652 .await
1653 });
1654 let mut client_a = make_test_client(client_a, &key_a).await?;
1655 handler_task.await.std_context("join")??;
1656
1657 info!("Create client B and connect it to the server.");
1658 let key_b = SecretKey::from_bytes(&rng.random());
1659 let public_key_b = key_b.public();
1660 let (client_b, rw_b) = tokio::io::duplex(10);
1661 let s = service.clone();
1662 let handler_task = tokio::spawn(async move {
1663 s.0.accept(
1664 MaybeTlsStream::Test(rw_b),
1665 Request::new(()).into_parts().0,
1666 Default::default(),
1667 )
1668 .await
1669 });
1670 let mut client_b = make_test_client(client_b, &key_b).await?;
1671 handler_task.await.std_context("join")??;
1672
1673 info!("Send message from A to B.");
1674 let msg = Datagrams::from(b"hello client b!!");
1675 client_a
1676 .send(ClientToRelayMsg::Datagrams {
1677 dst_endpoint_id: public_key_b,
1678 datagrams: msg.clone(),
1679 })
1680 .await?;
1681 match client_b.next().await.expect("eos")? {
1682 RelayToClientMsg::Datagrams {
1683 remote_endpoint_id,
1684 datagrams,
1685 } => {
1686 assert_eq!(public_key_a, remote_endpoint_id);
1687 assert_eq!(msg, datagrams);
1688 }
1689 msg => {
1690 bail_any!("expected ReceivedDatagrams msg, got {msg:?}");
1691 }
1692 }
1693
1694 info!("Send message from B to A.");
1695 let msg = Datagrams::from(b"nice to meet you client a!!");
1696 client_b
1697 .send(ClientToRelayMsg::Datagrams {
1698 dst_endpoint_id: public_key_a,
1699 datagrams: msg.clone(),
1700 })
1701 .await?;
1702 match client_a.next().await.expect("eos")? {
1703 RelayToClientMsg::Datagrams {
1704 remote_endpoint_id,
1705 datagrams,
1706 } => {
1707 assert_eq!(public_key_b, remote_endpoint_id);
1708 assert_eq!(msg, datagrams);
1709 }
1710 msg => {
1711 bail_any!("expected ReceivedDatagrams msg, got {msg:?}");
1712 }
1713 }
1714
1715 info!("Create client B and connect it to the server");
1716 let (new_client_b, new_rw_b) = tokio::io::duplex(10);
1717 let s = service.clone();
1718 let handler_task = tokio::spawn(async move {
1719 s.0.accept(
1720 MaybeTlsStream::Test(new_rw_b),
1721 Request::new(()).into_parts().0,
1722 Default::default(),
1723 )
1724 .await
1725 });
1726 let mut new_client_b = make_test_client(new_client_b, &key_b).await?;
1727 handler_task.await.std_context("join")??;
1728
1729 info!("Send message from A to B.");
1732 let msg = Datagrams::from(b"are you still there, b?!");
1733 client_a
1734 .send(ClientToRelayMsg::Datagrams {
1735 dst_endpoint_id: public_key_b,
1736 datagrams: msg.clone(),
1737 })
1738 .await?;
1739 match new_client_b.next().await.expect("eos")? {
1740 RelayToClientMsg::Datagrams {
1741 remote_endpoint_id,
1742 datagrams,
1743 } => {
1744 assert_eq!(public_key_a, remote_endpoint_id);
1745 assert_eq!(msg, datagrams);
1746 }
1747 msg => {
1748 bail_any!("expected ReceivedDatagrams msg, got {msg:?}");
1749 }
1750 }
1751
1752 info!("Send message from B to A.");
1753 let msg = Datagrams::from(b"just had a spot of trouble but I'm back now,a!!");
1754 new_client_b
1755 .send(ClientToRelayMsg::Datagrams {
1756 dst_endpoint_id: public_key_a,
1757 datagrams: msg.clone(),
1758 })
1759 .await?;
1760 match client_a.next().await.expect("eos")? {
1761 RelayToClientMsg::Datagrams {
1762 remote_endpoint_id,
1763 datagrams,
1764 } => {
1765 assert_eq!(public_key_b, remote_endpoint_id);
1766 assert_eq!(msg, datagrams);
1767 }
1768 msg => {
1769 bail_any!("expected ReceivedDatagrams msg, got {msg:?}");
1770 }
1771 }
1772
1773 info!("Close the server and clients");
1774 service.shutdown().await;
1775
1776 info!("Sending message from A to B fails");
1777 let res = client_a
1778 .send(ClientToRelayMsg::Datagrams {
1779 dst_endpoint_id: public_key_b,
1780 datagrams: Datagrams::from(b"try to send"),
1781 })
1782 .await;
1783 assert!(res.is_err());
1784 assert!(new_client_b.next().await.is_none());
1785 Ok(())
1786 }
1787
1788 #[tokio::test]
1789 #[traced_test]
1790 async fn test_establish_timeout() -> Result {
1791 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(42u64);
1792
1793 let server = ServerBuilder::new("127.0.0.1:0".parse().unwrap())
1795 .establish_timeout(Duration::from_millis(500))
1796 .spawn()
1797 .await?;
1798
1799 let addr = server.addr();
1800 let port = addr.port();
1801 let addr = if let std::net::IpAddr::V4(ipv4_addr) = addr.ip() {
1802 ipv4_addr
1803 } else {
1804 bail_any!("cannot get ipv4 addr from socket addr {addr:?}");
1805 };
1806 let relay_url: Url = format!("http://{addr}:{port}").parse().unwrap();
1807
1808 info!("opening lingering TCP connection (no upgrade)");
1810 let mut lingering = TcpStream::connect(format!("{addr}:{port}")).await?;
1811 lingering
1813 .write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n")
1814 .await?;
1815 let mut buf = [0u8; 1];
1817 let deadline = tokio::time::Instant::now() + Duration::from_secs(5);
1818 let read = tokio::time::timeout_at(deadline, lingering.read(&mut buf)).await;
1819 match read {
1821 Ok(Ok(0)) => info!("lingering connection closed by server (EOF)"),
1822 Ok(Err(e)) => info!("lingering connection closed by server (error: {e})"),
1823 other => bail_any!("expected lingering connection to be closed, got {other:?}"),
1824 }
1825
1826 info!("connecting a proper relay client");
1828 let key = SecretKey::from_bytes(&rng.random());
1829 let (_, mut client) = create_test_client(key, relay_url).await?;
1830
1831 tokio::time::sleep(Duration::from_millis(1000)).await;
1833
1834 client.send(ClientToRelayMsg::Ping([7u8; 8])).await?;
1836 let pong = client.next().await.expect("expected pong")?;
1837 assert!(matches!(pong, RelayToClientMsg::Pong { .. }));
1838 info!("established connection survived past the timeout");
1839
1840 client.close().await?;
1841 server.shutdown();
1842 Ok(())
1843 }
1844}