Show More
@@ -0,0 +1,97 b'' | |||||
|
1 | // Copyright 2018 Yuya Nishihara <yuya@tcha.org> | |||
|
2 | // | |||
|
3 | // This software may be used and distributed according to the terms of the | |||
|
4 | // GNU General Public License version 2 or any later version. | |||
|
5 | ||||
|
6 | //! Functions to send client-side fds over the command server channel. | |||
|
7 | ||||
|
8 | use futures::{Async, Future, Poll}; | |||
|
9 | use std::io; | |||
|
10 | use std::os::unix::io::AsRawFd; | |||
|
11 | use tokio_hglib::{Client, Connection}; | |||
|
12 | use tokio_hglib::codec::ChannelMessage; | |||
|
13 | use tokio_hglib::protocol::MessageLoop; | |||
|
14 | ||||
|
15 | use super::message; | |||
|
16 | use super::procutil; | |||
|
17 | ||||
|
18 | /// Future to send client-side fds over the command server channel. | |||
|
19 | /// | |||
|
20 | /// This works as follows: | |||
|
21 | /// 1. Client sends "attachio" request. | |||
|
22 | /// 2. Server sends back 1-byte input request. | |||
|
23 | /// 3. Client sends fds with 1-byte dummy payload in response. | |||
|
24 | /// 4. Server returns the number of the fds received. | |||
|
25 | /// | |||
|
26 | /// If the stderr is omitted, it will be redirected to the stdout. This | |||
|
27 | /// allows us to attach the pager stdin to both stdout and stderr, and | |||
|
28 | /// 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 C: Connection, | |||
|
32 | { | |||
|
33 | msg_loop: MessageLoop<C>, | |||
|
34 | stdin: I, | |||
|
35 | stdout: O, | |||
|
36 | stderr: Option<E>, | |||
|
37 | } | |||
|
38 | ||||
|
39 | impl<C, I, O, E> AttachIo<C, I, O, E> | |||
|
40 | where C: Connection + AsRawFd, | |||
|
41 | I: AsRawFd, | |||
|
42 | O: AsRawFd, | |||
|
43 | E: AsRawFd, | |||
|
44 | { | |||
|
45 | pub fn with_client(client: Client<C>, stdin: I, stdout: O, stderr: Option<E>) | |||
|
46 | -> AttachIo<C, I, O, E> { | |||
|
47 | let msg_loop = MessageLoop::start(client, b"attachio"); | |||
|
48 | AttachIo { msg_loop, stdin, stdout, stderr } | |||
|
49 | } | |||
|
50 | } | |||
|
51 | ||||
|
52 | impl<C, I, O, E> Future for AttachIo<C, I, O, E> | |||
|
53 | where C: Connection + AsRawFd, | |||
|
54 | I: AsRawFd, | |||
|
55 | O: AsRawFd, | |||
|
56 | E: AsRawFd, | |||
|
57 | { | |||
|
58 | type Item = Client<C>; | |||
|
59 | type Error = io::Error; | |||
|
60 | ||||
|
61 | fn poll(&mut self) -> Poll<Self::Item, Self::Error> { | |||
|
62 | loop { | |||
|
63 | let (client, msg) = try_ready!(self.msg_loop.poll()); | |||
|
64 | match msg { | |||
|
65 | ChannelMessage::Data(b'r', data) => { | |||
|
66 | let fd_cnt = message::parse_result_code(data)?; | |||
|
67 | if fd_cnt == 3 { | |||
|
68 | return Ok(Async::Ready(client)); | |||
|
69 | } else { | |||
|
70 | return Err(io::Error::new(io::ErrorKind::InvalidData, | |||
|
71 | "unexpected attachio result")); | |||
|
72 | } | |||
|
73 | } | |||
|
74 | ChannelMessage::Data(..) => { | |||
|
75 | // just ignore data sent to uninteresting (optional) channel | |||
|
76 | self.msg_loop = MessageLoop::resume(client); | |||
|
77 | } | |||
|
78 | ChannelMessage::InputRequest(1) => { | |||
|
79 | // this may fail with EWOULDBLOCK in theory, but the | |||
|
80 | // payload is quite small, and the send buffer should | |||
|
81 | // be empty so the operation will complete immediately | |||
|
82 | let sock_fd = client.as_raw_fd(); | |||
|
83 | let ifd = self.stdin.as_raw_fd(); | |||
|
84 | let ofd = self.stdout.as_raw_fd(); | |||
|
85 | let efd = self.stderr.as_ref().map_or(ofd, |f| f.as_raw_fd()); | |||
|
86 | procutil::send_raw_fds(sock_fd, &[ifd, ofd, efd])?; | |||
|
87 | self.msg_loop = MessageLoop::resume(client); | |||
|
88 | } | |||
|
89 | ChannelMessage::InputRequest(..) | ChannelMessage::LineRequest(..) | | |||
|
90 | ChannelMessage::SystemRequest(..) => { | |||
|
91 | return Err(io::Error::new(io::ErrorKind::InvalidData, | |||
|
92 | "unsupported request while attaching io")); | |||
|
93 | } | |||
|
94 | } | |||
|
95 | } | |||
|
96 | } | |||
|
97 | } |
@@ -4,8 +4,12 b'' | |||||
4 | // GNU General Public License version 2 or any later version. |
|
4 | // GNU General Public License version 2 or any later version. | |
5 |
|
5 | |||
6 | extern crate bytes; |
|
6 | extern crate bytes; | |
|
7 | #[macro_use] | |||
|
8 | extern crate futures; | |||
7 | extern crate libc; |
|
9 | extern crate libc; | |
|
10 | extern crate tokio; | |||
8 | extern crate tokio_hglib; |
|
11 | extern crate tokio_hglib; | |
9 |
|
12 | |||
|
13 | pub mod attachio; | |||
10 | pub mod message; |
|
14 | pub mod message; | |
11 | pub mod procutil; |
|
15 | pub mod procutil; |
General Comments 0
You need to be logged in to leave comments.
Login now