Show More
@@ -1,114 +1,73 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 | use futures::{try_ready, Async, Future, Poll}; | |
|
9 | 8 | use std::io; |
|
10 | 9 | use std::os::unix::io::AsRawFd; |
|
11 | 10 | use tokio_hglib::codec::ChannelMessage; |
|
12 |
use tokio_hglib:: |
|
|
13 | use tokio_hglib::{Client, Connection}; | |
|
11 | use tokio_hglib::{Connection, Protocol}; | |
|
14 | 12 | |
|
15 | 13 | use crate::message; |
|
16 | 14 | use crate::procutil; |
|
17 | 15 | |
|
18 |
/// |
|
|
16 | /// Sends client-side fds over the command server channel. | |
|
19 | 17 | /// |
|
20 | 18 | /// This works as follows: |
|
21 | 19 | /// 1. Client sends "attachio" request. |
|
22 | 20 | /// 2. Server sends back 1-byte input request. |
|
23 | 21 | /// 3. Client sends fds with 1-byte dummy payload in response. |
|
24 | 22 | /// 4. Server returns the number of the fds received. |
|
25 | 23 | /// |
|
26 | 24 | /// If the stderr is omitted, it will be redirected to the stdout. This |
|
27 | 25 | /// allows us to attach the pager stdin to both stdout and stderr, and |
|
28 | 26 | /// dispose of the client-side handle once attached. |
|
29 | #[must_use = "futures do nothing unless polled"] | |
|
30 | pub struct AttachIo<C, I, O, E> | |
|
31 | where | |
|
32 | C: Connection, | |
|
33 | { | |
|
34 | msg_loop: MessageLoop<C>, | |
|
35 | stdin: I, | |
|
36 | stdout: O, | |
|
37 | stderr: Option<E>, | |
|
38 | } | |
|
39 | ||
|
40 | impl<C, I, O, E> AttachIo<C, I, O, E> | |
|
41 | where | |
|
42 | C: Connection + AsRawFd, | |
|
43 | I: AsRawFd, | |
|
44 | O: AsRawFd, | |
|
45 | E: AsRawFd, | |
|
46 | { | |
|
47 | pub fn with_client( | |
|
48 | client: Client<C>, | |
|
49 | stdin: I, | |
|
50 | stdout: O, | |
|
51 | stderr: Option<E>, | |
|
52 | ) -> AttachIo<C, I, O, E> { | |
|
53 | let msg_loop = MessageLoop::start(client, b"attachio"); | |
|
54 | AttachIo { | |
|
55 | msg_loop, | |
|
56 | stdin, | |
|
57 | stdout, | |
|
58 | stderr, | |
|
59 | } | |
|
60 | } | |
|
61 | } | |
|
62 | ||
|
63 | impl<C, I, O, E> Future for AttachIo<C, I, O, E> | |
|
64 | where | |
|
65 | C: Connection + AsRawFd, | |
|
66 | I: AsRawFd, | |
|
67 | O: AsRawFd, | |
|
68 | E: AsRawFd, | |
|
69 | { | |
|
70 | type Item = Client<C>; | |
|
71 | type Error = io::Error; | |
|
72 | ||
|
73 | fn poll(&mut self) -> Poll<Self::Item, Self::Error> { | |
|
27 | pub async fn attach_io( | |
|
28 | proto: &mut Protocol<impl Connection + AsRawFd>, | |
|
29 | stdin: impl AsRawFd, | |
|
30 | stdout: impl AsRawFd, | |
|
31 | stderr: Option<impl AsRawFd>, | |
|
32 | ) -> io::Result<()> { | |
|
33 | // TODO: unindent | |
|
34 | { | |
|
35 | proto.send_command("attachio").await?; | |
|
74 | 36 | loop { |
|
75 | let (client, msg) = try_ready!(self.msg_loop.poll()); | |
|
76 | match msg { | |
|
37 | match proto.fetch_response().await? { | |
|
77 | 38 | ChannelMessage::Data(b'r', data) => { |
|
78 | 39 | let fd_cnt = message::parse_result_code(data)?; |
|
79 | 40 | if fd_cnt == 3 { |
|
80 |
return Ok( |
|
|
41 | return Ok(()); | |
|
81 | 42 | } else { |
|
82 | 43 | return Err(io::Error::new( |
|
83 | 44 | io::ErrorKind::InvalidData, |
|
84 | 45 | "unexpected attachio result", |
|
85 | 46 | )); |
|
86 | 47 | } |
|
87 | 48 | } |
|
88 | 49 | ChannelMessage::Data(..) => { |
|
89 | 50 | // just ignore data sent to uninteresting (optional) channel |
|
90 | self.msg_loop = MessageLoop::resume(client); | |
|
91 | 51 | } |
|
92 | 52 | ChannelMessage::InputRequest(1) => { |
|
93 | 53 | // this may fail with EWOULDBLOCK in theory, but the |
|
94 | 54 | // payload is quite small, and the send buffer should |
|
95 | 55 | // be empty so the operation will complete immediately |
|
96 |
let sock_fd = |
|
|
97 |
let ifd = |
|
|
98 |
let ofd = |
|
|
99 |
let efd = |
|
|
56 | let sock_fd = proto.as_raw_fd(); | |
|
57 | let ifd = stdin.as_raw_fd(); | |
|
58 | let ofd = stdout.as_raw_fd(); | |
|
59 | let efd = stderr.as_ref().map_or(ofd, |f| f.as_raw_fd()); | |
|
100 | 60 | procutil::send_raw_fds(sock_fd, &[ifd, ofd, efd])?; |
|
101 | self.msg_loop = MessageLoop::resume(client); | |
|
102 | 61 | } |
|
103 | 62 | ChannelMessage::InputRequest(..) |
|
104 | 63 | | ChannelMessage::LineRequest(..) |
|
105 | 64 | | ChannelMessage::SystemRequest(..) => { |
|
106 | 65 | return Err(io::Error::new( |
|
107 | 66 | io::ErrorKind::InvalidData, |
|
108 | 67 | "unsupported request while attaching io", |
|
109 | 68 | )); |
|
110 | 69 | } |
|
111 | 70 | } |
|
112 | 71 | } |
|
113 | 72 | } |
|
114 | 73 | } |
@@ -1,15 +1,15 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 | mod attachio; | |
|
7 | 7 | //mod clientext; |
|
8 | 8 | //pub mod locator; |
|
9 | 9 | pub mod message; |
|
10 | 10 | pub mod procutil; |
|
11 | 11 | //mod runcommand; |
|
12 | 12 | //mod uihandler; |
|
13 | 13 | |
|
14 | 14 | //pub use clientext::ChgClientExt; |
|
15 | 15 | //pub use uihandler::{ChgUiHandler, SystemHandler}; |
General Comments 0
You need to be logged in to leave comments.
Login now