@@ -1414,6 +1414,7 @@ impl DaemonState {
14141414 tokio:: spawn ( run_raw_dial_socket (
14151415 listener,
14161416 self . endpoint_rx ( ) ,
1417+ peer. to_string ( ) ,
14171418 peer_addr. clone ( ) ,
14181419 alpn,
14191420 listener_cancel. clone ( ) ,
@@ -5078,6 +5079,7 @@ async fn run_dial_tcp_listener(
50785079async fn run_raw_dial_socket (
50795080 listener : UnixListener ,
50805081 endpoint_rx : watch:: Receiver < CurrentEndpoint > ,
5082+ peer : String ,
50815083 peer_addr : EndpointAddr ,
50825084 alpn : Vec < u8 > ,
50835085 listener_cancel : CancellationToken ,
@@ -5109,6 +5111,7 @@ async fn run_raw_dial_socket(
51095111 }
51105112 } ;
51115113 let endpoint = endpoint_rx. borrow( ) . clone( ) ;
5114+ let peer = peer. clone( ) ;
51125115 let peer_addr = peer_addr. clone( ) ;
51135116 let alpn = alpn. clone( ) ;
51145117 let cancel = daemon_cancel. clone( ) ;
@@ -5123,6 +5126,7 @@ async fn run_raw_dial_socket(
51235126 match handle_raw_dial_socket_connection(
51245127 local,
51255128 endpoint,
5129+ peer,
51265130 peer_addr,
51275131 alpn,
51285132 peer_connections,
@@ -5143,23 +5147,74 @@ async fn run_raw_dial_socket(
51435147}
51445148
51455149async fn handle_raw_dial_socket_connection (
5146- local : UnixStream ,
5150+ mut local : UnixStream ,
51475151 endpoint : CurrentEndpoint ,
5152+ peer : String ,
51485153 peer_addr : EndpointAddr ,
51495154 alpn : Vec < u8 > ,
51505155 peer_connections : Arc < mux:: PeerConnections > ,
51515156) -> Result < ( ) > {
51525157 let protocol = std:: str:: from_utf8 ( & alpn) . context ( "protocol is not UTF-8" ) ?;
5153- let stream = peer_connections
5158+ let stream = match peer_connections
51545159 . open_stream (
51555160 & endpoint. endpoint ,
51565161 endpoint. generation ,
51575162 & peer_addr,
51585163 protocol,
51595164 mux:: StreamActivity :: Application ,
51605165 )
5161- . await ?;
5162- pipe_unix_iroh ( local, stream. send , stream. recv ) . await ?;
5166+ . await
5167+ {
5168+ Ok ( stream) => stream,
5169+ Err ( error) => {
5170+ if alpn == exec:: EXEC_ALPN {
5171+ let ( message, exit_code) = if mux:: is_permanent_stream_denial ( & error) {
5172+ (
5173+ format ! ( "refused service \" exec\" : {error}" ) ,
5174+ exec:: EXIT_EXEC_DISABLED ,
5175+ )
5176+ } else {
5177+ ( format ! ( "failed to start service \" exec\" : {error}" ) , 1 )
5178+ } ;
5179+ // Preserve the dial error for diagnostics and backoff. The
5180+ // frame is for the local CLI, which otherwise sees only EOF.
5181+ let _ = exec:: serve_exec_failure ( & mut local, & message, exit_code) . await ;
5182+ }
5183+ let context = format ! ( "dial to peer {peer:?} failed: {error}" ) ;
5184+ return Err ( error) . context ( context) ;
5185+ }
5186+ } ;
5187+ if alpn == exec:: EXEC_ALPN {
5188+ pipe_exec_unix_iroh ( local, stream. send , stream. recv ) . await ?;
5189+ } else {
5190+ pipe_unix_iroh ( local, stream. send , stream. recv ) . await ?;
5191+ }
5192+ Ok ( ( ) )
5193+ }
5194+
5195+ /// Keep receiving exec frames after the peer stops its receive direction.
5196+ ///
5197+ /// A policy refusal sends Error and Exit, then closes without reading the
5198+ /// command frame. That stopped send direction must not cancel the useful reply.
5199+ async fn pipe_exec_unix_iroh (
5200+ local : UnixStream ,
5201+ mut send : SendStream ,
5202+ mut recv : RecvStream ,
5203+ ) -> Result < ( ) > {
5204+ let ( mut local_read, mut local_write) = local. into_split ( ) ;
5205+ let to_remote = async {
5206+ tokio:: io:: copy ( & mut local_read, & mut send) . await ?;
5207+ send. finish ( ) ?;
5208+ Ok :: < ( ) , anyhow:: Error > ( ( ) )
5209+ } ;
5210+ let to_local = async {
5211+ tokio:: io:: copy ( & mut recv, & mut local_write) . await ?;
5212+ let _ = local_write. shutdown ( ) . await ;
5213+ Ok :: < ( ) , anyhow:: Error > ( ( ) )
5214+ } ;
5215+ let ( to_remote, to_local) = tokio:: join!( to_remote, to_local) ;
5216+ to_local?;
5217+ to_remote?;
51635218 Ok ( ( ) )
51645219}
51655220
0 commit comments