attachio.rs
68 lines
| 2.4 KiB
| application/rls-services+xml
|
RustLexer
Yuya Nishihara
|
r40008 | // Copyright 2018 Yuya Nishihara <yuya@tcha.org> | ||
// | ||||
// This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | ||||
//! Functions to send client-side fds over the command server channel. | ||||
use std::io; | ||||
use std::os::unix::io::AsRawFd; | ||||
use tokio_hglib::codec::ChannelMessage; | ||||
Yuya Nishihara
|
r45232 | use tokio_hglib::{Connection, Protocol}; | ||
Yuya Nishihara
|
r40008 | |||
Yuya Nishihara
|
r45180 | use crate::message; | ||
use crate::procutil; | ||||
Yuya Nishihara
|
r40008 | |||
Yuya Nishihara
|
r45232 | /// Sends client-side fds over the command server channel. | ||
Yuya Nishihara
|
r40008 | /// | ||
/// This works as follows: | ||||
/// 1. Client sends "attachio" request. | ||||
/// 2. Server sends back 1-byte input request. | ||||
/// 3. Client sends fds with 1-byte dummy payload in response. | ||||
/// 4. Server returns the number of the fds received. | ||||
/// | ||||
Yuya Nishihara
|
r45233 | /// The client-side fds may be dropped once duplicated to the server. | ||
Yuya Nishihara
|
r45232 | pub async fn attach_io( | ||
proto: &mut Protocol<impl Connection + AsRawFd>, | ||||
Yuya Nishihara
|
r45233 | stdin: &impl AsRawFd, | ||
stdout: &impl AsRawFd, | ||||
stderr: &impl AsRawFd, | ||||
Yuya Nishihara
|
r45232 | ) -> io::Result<()> { | ||
Yuya Nishihara
|
r45240 | proto.send_command("attachio").await?; | ||
loop { | ||||
match proto.fetch_response().await? { | ||||
ChannelMessage::Data(b'r', data) => { | ||||
let fd_cnt = message::parse_result_code(data)?; | ||||
if fd_cnt == 3 { | ||||
return Ok(()); | ||||
} else { | ||||
Gregory Szorc
|
r44270 | return Err(io::Error::new( | ||
io::ErrorKind::InvalidData, | ||||
Yuya Nishihara
|
r45240 | "unexpected attachio result", | ||
Gregory Szorc
|
r44270 | )); | ||
Yuya Nishihara
|
r40008 | } | ||
} | ||||
Yuya Nishihara
|
r45240 | ChannelMessage::Data(..) => { | ||
// just ignore data sent to uninteresting (optional) channel | ||||
} | ||||
ChannelMessage::InputRequest(1) => { | ||||
// this may fail with EWOULDBLOCK in theory, but the | ||||
// payload is quite small, and the send buffer should | ||||
// be empty so the operation will complete immediately | ||||
let sock_fd = proto.as_raw_fd(); | ||||
let ifd = stdin.as_raw_fd(); | ||||
let ofd = stdout.as_raw_fd(); | ||||
let efd = stderr.as_raw_fd(); | ||||
procutil::send_raw_fds(sock_fd, &[ifd, ofd, efd])?; | ||||
} | ||||
ChannelMessage::InputRequest(..) | ||||
| ChannelMessage::LineRequest(..) | ||||
| ChannelMessage::SystemRequest(..) => { | ||||
return Err(io::Error::new( | ||||
io::ErrorKind::InvalidData, | ||||
"unsupported request while attaching io", | ||||
)); | ||||
} | ||||
Yuya Nishihara
|
r40008 | } | ||
} | ||||
} | ||||