Show More
@@ -1,73 +1,71 b'' | |||
|
1 | 1 | // Copyright 2018 Yuya Nishihara <yuya@tcha.org> |
|
2 | 2 | // |
|
3 | 3 | // This software may be used and distributed according to the terms of the |
|
4 | 4 | // GNU General Public License version 2 or any later version. |
|
5 | 5 | |
|
6 | 6 | //! Functions to send client-side fds over the command server channel. |
|
7 | 7 | |
|
8 | 8 | use std::io; |
|
9 | 9 | use std::os::unix::io::AsRawFd; |
|
10 | 10 | use tokio_hglib::codec::ChannelMessage; |
|
11 | 11 | use tokio_hglib::{Connection, Protocol}; |
|
12 | 12 | |
|
13 | 13 | use crate::message; |
|
14 | 14 | use crate::procutil; |
|
15 | 15 | |
|
16 | 16 | /// Sends client-side fds over the command server channel. |
|
17 | 17 | /// |
|
18 | 18 | /// This works as follows: |
|
19 | 19 | /// 1. Client sends "attachio" request. |
|
20 | 20 | /// 2. Server sends back 1-byte input request. |
|
21 | 21 | /// 3. Client sends fds with 1-byte dummy payload in response. |
|
22 | 22 | /// 4. Server returns the number of the fds received. |
|
23 | 23 | /// |
|
24 | /// If the stderr is omitted, it will be redirected to the stdout. This | |
|
25 | /// allows us to attach the pager stdin to both stdout and stderr, and | |
|
26 | /// dispose of the client-side handle once attached. | |
|
24 | /// The client-side fds may be dropped once duplicated to the server. | |
|
27 | 25 | pub async fn attach_io( |
|
28 | 26 | proto: &mut Protocol<impl Connection + AsRawFd>, |
|
29 | stdin: impl AsRawFd, | |
|
30 | stdout: impl AsRawFd, | |
|
31 |
stderr: |
|
|
27 | stdin: &impl AsRawFd, | |
|
28 | stdout: &impl AsRawFd, | |
|
29 | stderr: &impl AsRawFd, | |
|
32 | 30 | ) -> io::Result<()> { |
|
33 | 31 | // TODO: unindent |
|
34 | 32 | { |
|
35 | 33 | proto.send_command("attachio").await?; |
|
36 | 34 | loop { |
|
37 | 35 | match proto.fetch_response().await? { |
|
38 | 36 | ChannelMessage::Data(b'r', data) => { |
|
39 | 37 | let fd_cnt = message::parse_result_code(data)?; |
|
40 | 38 | if fd_cnt == 3 { |
|
41 | 39 | return Ok(()); |
|
42 | 40 | } else { |
|
43 | 41 | return Err(io::Error::new( |
|
44 | 42 | io::ErrorKind::InvalidData, |
|
45 | 43 | "unexpected attachio result", |
|
46 | 44 | )); |
|
47 | 45 | } |
|
48 | 46 | } |
|
49 | 47 | ChannelMessage::Data(..) => { |
|
50 | 48 | // just ignore data sent to uninteresting (optional) channel |
|
51 | 49 | } |
|
52 | 50 | ChannelMessage::InputRequest(1) => { |
|
53 | 51 | // this may fail with EWOULDBLOCK in theory, but the |
|
54 | 52 | // payload is quite small, and the send buffer should |
|
55 | 53 | // be empty so the operation will complete immediately |
|
56 | 54 | let sock_fd = proto.as_raw_fd(); |
|
57 | 55 | let ifd = stdin.as_raw_fd(); |
|
58 | 56 | let ofd = stdout.as_raw_fd(); |
|
59 |
let efd = stderr. |
|
|
57 | let efd = stderr.as_raw_fd(); | |
|
60 | 58 | procutil::send_raw_fds(sock_fd, &[ifd, ofd, efd])?; |
|
61 | 59 | } |
|
62 | 60 | ChannelMessage::InputRequest(..) |
|
63 | 61 | | ChannelMessage::LineRequest(..) |
|
64 | 62 | | ChannelMessage::SystemRequest(..) => { |
|
65 | 63 | return Err(io::Error::new( |
|
66 | 64 | io::ErrorKind::InvalidData, |
|
67 | 65 | "unsupported request while attaching io", |
|
68 | 66 | )); |
|
69 | 67 | } |
|
70 | 68 | } |
|
71 | 69 | } |
|
72 | 70 | } |
|
73 | 71 | } |
General Comments 0
You need to be logged in to leave comments.
Login now