1use std::{
2 fmt,
3 io::{self, IoSlice},
4 pin::Pin,
5 process::Stdio,
6 task::{Context, Poll, ready},
7 time::Duration,
8};
9
10use dolang_rpc::handle::DefaultHandle;
11use futures::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufReader};
12use serde::{Deserialize, Serialize};
13use tokio::{
14 io::{AsyncRead as TokioRead, AsyncWrite as TokioWrite, ReadBuf},
15 task::{JoinError, JoinHandle},
16};
17
18use crate::{
19 STREAM_CHUNK_SIZE, SessionMode, Vfs, VfsInner, client, direct,
20 error::{Error, ErrorKind, Result},
21 file::{File, FileInner},
22 path,
23 target::OperatingSystem,
24};
25
26mod foreign;
27
28pub(crate) use foreign::ProcessFamily;
29pub use foreign::{Process, ProcessExit, ProcessInfo, Processes, StartTime};
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
33pub enum ProcessStatus {
34 Exited(i32),
35 Signaled(i32),
36}
37
38impl ProcessStatus {
39 pub const fn success(self) -> bool {
41 matches!(self, Self::Exited(0))
42 }
43
44 pub const fn code(self) -> Option<i32> {
46 match self {
47 Self::Exited(code) => Some(code),
48 Self::Signaled(_) => None,
49 }
50 }
51
52 pub const fn signal(self) -> Option<i32> {
54 match self {
55 Self::Exited(_) => None,
56 Self::Signaled(signal) => Some(signal),
57 }
58 }
59
60 pub(crate) fn from_native(status: std::process::ExitStatus) -> io::Result<Self> {
61 if let Some(code) = status.code() {
62 return Ok(Self::Exited(code));
63 }
64 #[cfg(unix)]
65 {
66 use std::os::unix::process::ExitStatusExt;
67 if let Some(signal) = status.signal() {
68 return Ok(Self::Signaled(signal));
69 }
70 }
71 Err(io::Error::new(
72 io::ErrorKind::InvalidData,
73 "process returned an unrepresentable terminal status",
74 ))
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
80pub enum ProcessControl {
81 Foreground,
83 Background,
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
89#[non_exhaustive]
90pub enum Signal {
91 Hup,
92 Int,
93 Quit,
94 Ill,
95 Trap,
96 Abrt,
97 Emt,
98 Fpe,
99 Kill,
100 Bus,
101 Segv,
102 Sys,
103 Pipe,
104 Alrm,
105 Term,
106 Urg,
107 Stop,
108 Tstp,
109 Cont,
110 Chld,
111 Ttin,
112 Ttou,
113 Io,
114 Xcpu,
115 Xfsz,
116 Vtalrm,
117 Prof,
118 Winch,
119 Info,
120 Usr1,
121 Usr2,
122 Stkflt,
123 Pwr,
124 Thr,
125 Librt,
126 Number(i32),
127}
128
129impl Signal {
130 pub fn is_supported(self, operating_system: OperatingSystem) -> bool {
132 use OperatingSystem::{FreeBsd, Linux, Macos, Windows};
133 match self {
134 Self::Emt | Self::Info => matches!(operating_system, FreeBsd | Macos),
135 Self::Stkflt | Self::Pwr => operating_system == Linux,
136 Self::Thr | Self::Librt => operating_system == FreeBsd,
137 Self::Number(_) => operating_system != Windows,
138 _ => operating_system != Windows,
139 }
140 }
141}
142enum CommandInner<'a> {
143 Client(client::Command<'a>),
144 Direct(direct::Command<'a>),
145}
146
147pub enum ChildIn {
149 Pipe(PipeRecv),
151 File(File),
157 Reader(Box<dyn AsyncRead + Send + Unpin>),
163}
164
165pub enum ChildOut {
167 Pipe(PipeSend),
169 File(File),
175 Writer(Box<dyn AsyncWrite + Send + Unpin>),
181}
182
183impl ChildIn {
184 pub fn reader(reader: impl AsyncRead + Send + Unpin + 'static) -> Self {
186 Self::Reader(Box::new(reader))
187 }
188}
189
190impl ChildOut {
191 pub fn writer(writer: impl AsyncWrite + Send + Unpin + 'static) -> Self {
193 Self::Writer(Box::new(writer))
194 }
195}
196
197impl fmt::Debug for ChildIn {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 match self {
200 Self::Pipe(pipe) => f.debug_tuple("Pipe").field(pipe).finish(),
201 Self::File(file) => f.debug_tuple("File").field(file).finish(),
202 Self::Reader(_) => f.debug_tuple("Reader").finish_non_exhaustive(),
203 }
204 }
205}
206
207impl fmt::Debug for ChildOut {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 match self {
210 Self::Pipe(pipe) => f.debug_tuple("Pipe").field(pipe).finish(),
211 Self::File(file) => f.debug_tuple("File").field(file).finish(),
212 Self::Writer(_) => f.debug_tuple("Writer").finish_non_exhaustive(),
213 }
214 }
215}
216
217pub(crate) enum SpawnIn {
220 Pipe(PipeRecv),
221 File(File),
222}
223
224pub(crate) enum SpawnOut {
227 Pipe(PipeSend),
228 File(File),
229}
230
231impl From<PipeRecv> for ChildIn {
232 fn from(pipe: PipeRecv) -> Self {
233 Self::Pipe(pipe)
234 }
235}
236
237impl From<File> for ChildIn {
238 fn from(file: File) -> Self {
239 Self::File(file)
240 }
241}
242
243impl From<PipeSend> for ChildOut {
244 fn from(pipe: PipeSend) -> Self {
245 Self::Pipe(pipe)
246 }
247}
248
249impl From<File> for ChildOut {
250 fn from(file: File) -> Self {
251 Self::File(file)
252 }
253}
254
255pub struct Command<'a> {
258 inner: CommandInner<'a>,
259 vfs: Vfs,
260 stdin: Option<ChildIn>,
261 stdout: Option<ChildOut>,
262 stderr: Option<ChildOut>,
263}
264
265impl<'a> Command<'a> {
266 pub(crate) fn new(vfs: &'a Vfs, program: path::Path<'_>) -> Self {
267 let inner = match &vfs.inner {
268 VfsInner::Client(client) => CommandInner::Client(client.command(program)),
269 VfsInner::Direct(direct) => CommandInner::Direct(direct.command(program)),
270 };
271 Self {
272 inner,
273 vfs: vfs.clone(),
274 stdin: None,
275 stdout: None,
276 stderr: None,
277 }
278 }
279}
280
281enum ChildInner {
282 Client(client::Child),
283 Direct(Box<direct::Child>),
284}
285
286#[derive(Default)]
297struct PendingRelays {
298 inputs: Vec<(RelaySource, PipeSend)>,
299 outputs: Vec<(PipeRecv, RelaySink)>,
300}
301
302type RelaySource = Box<dyn AsyncRead + Send + Unpin>;
303type RelaySink = Box<dyn AsyncWrite + Send + Unpin>;
304
305impl PendingRelays {
306 fn start(self) -> ActiveRelays {
307 ActiveRelays {
308 inputs: self
309 .inputs
310 .into_iter()
311 .map(|(src, dst)| tokio::spawn(relay(src, dst)))
312 .collect(),
313 outputs: self
314 .outputs
315 .into_iter()
316 .map(|(src, dst)| tokio::spawn(relay(src, dst)))
317 .collect(),
318 error: None,
319 }
320 }
321}
322
323#[derive(Default)]
324struct ActiveRelays {
325 inputs: Vec<JoinHandle<io::Result<()>>>,
326 outputs: Vec<JoinHandle<io::Result<()>>>,
327 error: Option<io::Error>,
329}
330
331impl ActiveRelays {
332 fn abort_inputs(&mut self) {
333 for handle in self.inputs.drain(..) {
334 handle.abort();
335 }
336 }
337
338 fn record(&mut self, result: std::result::Result<io::Result<()>, JoinError>) {
340 let error = match result {
341 Ok(Ok(())) => return,
342 Ok(Err(error)) => error,
343 Err(error) => match error.try_into_panic() {
344 Ok(panic) => std::panic::resume_unwind(panic),
345 Err(_) => return,
346 },
347 };
348 self.error.get_or_insert(error);
349 }
350
351 async fn finish(&mut self) {
363 for handle in std::mem::take(&mut self.inputs) {
364 if !handle.is_finished() {
365 handle.abort();
366 continue;
367 }
368 match handle.await {
369 Ok(Err(error)) if error.kind() == io::ErrorKind::BrokenPipe => {}
370 result => self.record(result),
371 }
372 }
373 for handle in std::mem::take(&mut self.outputs) {
374 let result = handle.await;
375 self.record(result);
376 }
377 }
378
379 fn abandon(&mut self) {
382 self.abort_inputs();
383 for handle in self.outputs.drain(..) {
384 handle.abort();
385 }
386 }
387}
388
389impl Drop for ActiveRelays {
390 fn drop(&mut self) {
391 self.abandon();
392 }
393}
394
395pub struct Child {
397 inner: ChildInner,
398 relays: ActiveRelays,
399}
400
401impl Child {
402 pub fn relay_error(&mut self) -> Option<io::Error> {
408 self.relays.error.take()
409 }
410
411 pub async fn wait(&mut self) -> Result<ProcessStatus> {
413 let status = match &mut self.inner {
414 ChildInner::Client(child) => child.wait().await,
415 ChildInner::Direct(child) => child.wait().await,
416 }?;
417 self.relays.finish().await;
418 Ok(status)
419 }
420
421 pub async fn terminate(mut self) -> Result<Option<ProcessStatus>> {
423 self.relays.abort_inputs();
424 let result = match self.inner {
425 ChildInner::Client(child) => child.terminate().await,
426 ChildInner::Direct(child) => child.terminate().await,
427 };
428 if result.as_ref().is_ok_and(Option::is_some) {
429 self.relays.finish().await;
430 } else {
431 self.relays.abandon();
432 }
433 result
434 }
435}
436
437fn is_direct_recv(target: &Vfs, stdio: &PipeRecv) -> bool {
440 match (&target.inner, &stdio.0) {
441 (VfsInner::Direct(_), PipeRecvInner::Native(_)) => true,
442 (VfsInner::Client(client), PipeRecvInner::Remote(remote)) => {
443 client.is_same_vfs(remote.client())
444 }
445 (VfsInner::Client(client), PipeRecvInner::Native(_)) => {
446 client.mode() == SessionMode::Native
447 }
448 _ => false,
449 }
450}
451
452fn is_direct_send(target: &Vfs, stdio: &PipeSend) -> bool {
455 match (&target.inner, &stdio.0) {
456 (VfsInner::Direct(_), PipeSendInner::Native(_)) => true,
457 (VfsInner::Client(client), PipeSendInner::Remote(remote)) => {
458 client.is_same_vfs(remote.client())
459 }
460 (VfsInner::Client(client), PipeSendInner::Native(_)) => {
461 client.mode() == SessionMode::Native
462 }
463 _ => false,
464 }
465}
466
467fn is_direct_file(target: &Vfs, file: &File) -> bool {
470 match (&target.inner, &file.inner) {
471 (VfsInner::Direct(_), FileInner::Direct(_)) => true,
472 (VfsInner::Client(client), FileInner::Client(file)) => client.is_same_vfs(file.client()),
473 (VfsInner::Client(client), FileInner::Direct(_)) => client.mode() == SessionMode::Native,
474 _ => false,
475 }
476}
477
478async fn classify_recv(
482 target: &Vfs,
483 stdio: ChildIn,
484 relays: &mut PendingRelays,
485) -> Result<SpawnIn> {
486 let source: RelaySource = match stdio {
487 ChildIn::Pipe(pipe) if is_direct_recv(target, &pipe) => return Ok(SpawnIn::Pipe(pipe)),
488 ChildIn::File(file) if is_direct_file(target, &file) => return Ok(SpawnIn::File(file)),
489 ChildIn::Pipe(pipe) => Box::new(pipe),
490 ChildIn::File(file) => Box::new(file),
491 ChildIn::Reader(reader) => reader,
492 };
493 let (send, recv) = target.pipe(None).await?;
494 relays.inputs.push((source, send));
495 Ok(SpawnIn::Pipe(recv))
496}
497
498async fn classify_send(
502 target: &Vfs,
503 stdio: ChildOut,
504 relays: &mut PendingRelays,
505) -> Result<SpawnOut> {
506 let sink: RelaySink = match stdio {
507 ChildOut::Pipe(pipe) if is_direct_send(target, &pipe) => return Ok(SpawnOut::Pipe(pipe)),
508 ChildOut::File(file) if is_direct_file(target, &file) => return Ok(SpawnOut::File(file)),
509 ChildOut::Pipe(pipe) => Box::new(pipe),
510 ChildOut::File(file) => Box::new(file),
511 ChildOut::Writer(writer) => writer,
512 };
513 let (send, recv) = target.pipe(None).await?;
514 relays.outputs.push((recv, sink));
515 Ok(SpawnOut::Pipe(send))
516}
517
518impl<'a> Command<'a> {
519 pub fn arg(&mut self, arg: &str) -> &mut Self {
521 match &mut self.inner {
522 CommandInner::Client(builder) => {
523 builder.arg(arg);
524 }
525 CommandInner::Direct(builder) => {
526 builder.arg(arg);
527 }
528 }
529 self
530 }
531
532 pub fn env(&mut self, key: &str, val: &str) -> &mut Self {
534 match &mut self.inner {
535 CommandInner::Client(builder) => {
536 builder.env(key, val);
537 }
538 CommandInner::Direct(builder) => {
539 builder.env(key, val);
540 }
541 }
542 self
543 }
544
545 pub fn env_remove(&mut self, key: &str) -> &mut Self {
547 match &mut self.inner {
548 CommandInner::Client(builder) => {
549 builder.env_remove(key);
550 }
551 CommandInner::Direct(builder) => {
552 builder.env_remove(key);
553 }
554 }
555 self
556 }
557
558 pub fn current_dir(&mut self, dir: path::Path<'_>) -> &mut Self {
560 match &mut self.inner {
561 CommandInner::Client(builder) => {
562 builder.current_dir(dir);
563 }
564 CommandInner::Direct(builder) => {
565 builder.current_dir(dir);
566 }
567 }
568 self
569 }
570
571 pub fn stdin(&mut self, stdio: impl Into<ChildIn>) -> Result<&mut Self> {
573 self.stdin = Some(stdio.into());
574 Ok(self)
575 }
576
577 pub fn stdout(&mut self, stdio: impl Into<ChildOut>) -> Result<&mut Self> {
579 self.stdout = Some(stdio.into());
580 Ok(self)
581 }
582
583 pub fn stdin_inherit(&mut self) -> Result<&mut Self> {
589 self.stdin = None;
590 match &mut self.inner {
591 CommandInner::Client(builder) => {
592 builder.stdin_inherit()?;
593 }
594 CommandInner::Direct(builder) => {
595 builder.stdin_inherit()?;
596 }
597 }
598 Ok(self)
599 }
600
601 pub fn stdout_inherit(&mut self) -> Result<&mut Self> {
603 self.stdout = None;
604 match &mut self.inner {
605 CommandInner::Client(builder) => {
606 builder.stdout_inherit()?;
607 }
608 CommandInner::Direct(builder) => {
609 builder.stdout_inherit()?;
610 }
611 }
612 Ok(self)
613 }
614
615 pub fn stdout_inherit_stderr(&mut self) -> Result<&mut Self> {
618 self.stdout = None;
619 match &mut self.inner {
620 CommandInner::Client(builder) => {
621 builder.stdout_inherit_stderr()?;
622 }
623 CommandInner::Direct(builder) => {
624 builder.stdout_inherit_stderr()?;
625 }
626 }
627 Ok(self)
628 }
629
630 pub fn stdin_null(&mut self) -> &mut Self {
632 self.stdin = None;
633 match &mut self.inner {
634 CommandInner::Client(builder) => {
635 builder.stdin_null();
636 }
637 CommandInner::Direct(builder) => {
638 builder.stdin_null();
639 }
640 }
641 self
642 }
643
644 pub fn stdout_null(&mut self) -> &mut Self {
646 self.stdout = None;
647 match &mut self.inner {
648 CommandInner::Client(builder) => {
649 builder.stdout_null();
650 }
651 CommandInner::Direct(builder) => {
652 builder.stdout_null();
653 }
654 }
655 self
656 }
657
658 pub fn stderr(&mut self, stdio: impl Into<ChildOut>) -> Result<&mut Self> {
660 self.stderr = Some(stdio.into());
661 Ok(self)
662 }
663
664 pub(crate) fn stdin_native(&mut self, stdio: Stdio) -> Result<&mut Self> {
668 self.stdin = None;
669 self.direct_inner()?.stdin_native(stdio);
670 Ok(self)
671 }
672
673 pub(crate) fn stdout_native(&mut self, stdio: Stdio) -> Result<&mut Self> {
677 self.stdout = None;
678 self.direct_inner()?.stdout_native(stdio);
679 Ok(self)
680 }
681
682 pub(crate) fn stderr_native(&mut self, stdio: Stdio) -> Result<&mut Self> {
686 self.stderr = None;
687 self.direct_inner()?.stderr_native(stdio);
688 Ok(self)
689 }
690
691 fn direct_inner(&mut self) -> Result<&mut direct::Command<'a>> {
692 match &mut self.inner {
693 CommandInner::Direct(builder) => Ok(builder),
694 CommandInner::Client(_) => Err(Error::new(
695 ErrorKind::InvalidInput,
696 "a native handle cannot be handed to a remote process",
697 )),
698 }
699 }
700
701 pub fn stderr_inherit(&mut self) -> Result<&mut Self> {
703 self.stderr = None;
704 match &mut self.inner {
705 CommandInner::Client(builder) => {
706 builder.stderr_inherit()?;
707 }
708 CommandInner::Direct(builder) => {
709 builder.stderr_inherit()?;
710 }
711 }
712 Ok(self)
713 }
714
715 pub fn stderr_to_stdout(&mut self) -> Result<&mut Self> {
718 self.stderr = None;
719 match &mut self.inner {
720 CommandInner::Client(builder) => {
721 builder.stderr_to_stdout()?;
722 }
723 CommandInner::Direct(builder) => {
724 builder.stderr_to_stdout()?;
725 }
726 }
727 Ok(self)
728 }
729
730 pub fn stderr_inherit_stdout(&mut self) -> Result<&mut Self> {
733 self.stderr = None;
734 match &mut self.inner {
735 CommandInner::Client(builder) => {
736 builder.stderr_inherit_stdout()?;
737 }
738 CommandInner::Direct(builder) => {
739 builder.stderr_inherit_stdout()?;
740 }
741 }
742 Ok(self)
743 }
744
745 pub fn stderr_null(&mut self) -> &mut Self {
747 self.stderr = None;
748 match &mut self.inner {
749 CommandInner::Client(builder) => {
750 builder.stderr_null();
751 }
752 CommandInner::Direct(builder) => {
753 builder.stderr_null();
754 }
755 }
756 self
757 }
758
759 pub fn process_control(&mut self, control: ProcessControl) -> &mut Self {
761 match &mut self.inner {
762 CommandInner::Client(builder) => {
763 builder.process_control(control);
764 }
765 CommandInner::Direct(builder) => {
766 builder.process_control(control);
767 }
768 }
769 self
770 }
771
772 pub fn termination_policy(&mut self, policy: TerminationPolicy) -> &mut Self {
774 match &mut self.inner {
775 CommandInner::Client(builder) => {
776 builder.termination_policy(policy);
777 }
778 CommandInner::Direct(builder) => {
779 builder.termination_policy(policy);
780 }
781 }
782 self
783 }
784
785 pub async fn spawn(mut self) -> Result<Child> {
787 let mut relays = PendingRelays::default();
788 if let Some(stdio) = self.stdin.take() {
789 let stdio = classify_recv(&self.vfs, stdio, &mut relays).await?;
790 match &mut self.inner {
791 CommandInner::Client(builder) => {
792 builder.stdin(stdio)?;
793 }
794 CommandInner::Direct(builder) => {
795 builder.stdin(stdio)?;
796 }
797 }
798 }
799 if let Some(stdio) = self.stdout.take() {
800 let stdio = classify_send(&self.vfs, stdio, &mut relays).await?;
801 match &mut self.inner {
802 CommandInner::Client(builder) => {
803 builder.stdout(stdio)?;
804 }
805 CommandInner::Direct(builder) => {
806 builder.stdout(stdio)?;
807 }
808 }
809 }
810 if let Some(stdio) = self.stderr.take() {
811 let stdio = classify_send(&self.vfs, stdio, &mut relays).await?;
812 match &mut self.inner {
813 CommandInner::Client(builder) => {
814 builder.stderr(stdio)?;
815 }
816 CommandInner::Direct(builder) => {
817 builder.stderr(stdio)?;
818 }
819 }
820 }
821 let inner = match self.inner {
822 CommandInner::Client(builder) => builder.spawn().await.map(ChildInner::Client),
823 CommandInner::Direct(builder) => builder
824 .spawn()
825 .await
826 .map(|x| ChildInner::Direct(Box::new(x))),
827 }?;
828 Ok(Child {
829 inner,
830 relays: relays.start(),
831 })
832 }
833}
834
835#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
837pub struct TerminationPolicy {
838 pub(crate) signal: Signal,
840 pub(crate) grace: Duration,
842 pub(crate) force: bool,
844}
845
846impl TerminationPolicy {
847 pub const fn new(signal: Signal, grace: Duration, force: bool) -> Self {
849 Self {
850 signal,
851 grace,
852 force,
853 }
854 }
855 pub const fn signal(self) -> Signal {
857 self.signal
858 }
859 pub const fn grace(self) -> Duration {
861 self.grace
862 }
863 pub const fn force(self) -> bool {
865 self.force
866 }
867 pub fn set_signal(&mut self, signal: Signal) -> &mut Self {
869 self.signal = signal;
870 self
871 }
872 pub fn set_grace(&mut self, grace: Duration) -> &mut Self {
874 self.grace = grace;
875 self
876 }
877 pub fn set_force(&mut self, force: bool) -> &mut Self {
879 self.force = force;
880 self
881 }
882}
883
884impl Default for TerminationPolicy {
885 fn default() -> Self {
886 Self {
887 signal: Signal::Term,
888 grace: Duration::from_secs(5),
889 force: true,
890 }
891 }
892}
893
894#[cfg(test)]
895mod policy_tests {
896 use super::{Signal, TerminationPolicy};
897 use std::time::Duration;
898
899 #[test]
900 fn termination_policy_construction_and_mutation() {
901 let mut policy = TerminationPolicy::new(Signal::Int, Duration::from_secs(2), false);
902 assert_eq!(policy.signal(), Signal::Int);
903 assert_eq!(policy.grace(), Duration::from_secs(2));
904 assert!(!policy.force());
905 policy
906 .set_signal(Signal::Term)
907 .set_grace(Duration::from_secs(3))
908 .set_force(true);
909 assert_eq!(
910 policy,
911 TerminationPolicy::new(Signal::Term, Duration::from_secs(3), true)
912 );
913 }
914}
915
916#[cfg(unix)]
917use std::os::fd::{AsFd, OwnedFd};
918#[cfg(windows)]
919use std::{
920 io::{PipeReader, PipeWriter, Read as _, Write as _},
921 os::windows::io::OwnedHandle,
922 sync::Arc,
923};
924#[derive(Debug)]
926pub struct PipeSend(pub(crate) PipeSendInner);
927
928#[derive(Debug)]
929pub(crate) enum PipeSendInner {
930 Native(NativePipeSend),
932 Remote(crate::client::RemotePipeSend),
934}
935
936#[derive(Debug)]
938pub struct PipeRecv(pub(crate) PipeRecvInner);
939
940#[derive(Debug)]
941pub(crate) enum PipeRecvInner {
942 Native(NativePipeRecv),
944 Remote(crate::client::RemotePipeRecv),
946}
947
948#[cfg(unix)]
950pub(crate) type NativePipeSend = tokio::net::unix::pipe::Sender;
951
952#[cfg(unix)]
954pub(crate) type NativePipeRecv = tokio::net::unix::pipe::Receiver;
955
956#[cfg(windows)]
958#[derive(Debug)]
959pub(crate) struct NativePipeSend {
960 inner: Arc<PipeWriter>,
961 pending: Option<JoinHandle<io::Result<usize>>>,
962}
963
964#[cfg(windows)]
966#[derive(Debug)]
967pub(crate) struct NativePipeRecv {
968 inner: Arc<PipeReader>,
969 pending: Option<JoinHandle<(Vec<u8>, io::Result<usize>)>>,
970 ready: Option<(Vec<u8>, usize)>,
971}
972
973pub(crate) async fn relay<R, W>(src: R, mut dst: W) -> io::Result<()>
976where
977 R: AsyncRead + Unpin,
978 W: AsyncWrite + Unpin,
979{
980 let mut src = BufReader::with_capacity(STREAM_CHUNK_SIZE, src);
981 let copied = futures::io::copy_buf(&mut src, &mut dst).await;
982 let closed = dst.close().await;
983 copied?;
984 closed
985}
986
987pub(crate) fn pipe(buf_size: Option<usize>) -> io::Result<(PipeSend, PipeRecv)> {
993 #[cfg(unix)]
994 {
995 let (send, recv) = tokio::net::unix::pipe::pipe()?;
996 if let Some(size) = buf_size {
997 use std::os::fd::AsRawFd;
998 set_pipe_buffer_size(send.as_raw_fd(), size);
999 }
1000 Ok((
1001 PipeSend(PipeSendInner::Native(send)),
1002 PipeRecv(PipeRecvInner::Native(recv)),
1003 ))
1004 }
1005 #[cfg(windows)]
1006 {
1007 let (recv, send) = match buf_size {
1008 Some(size) => create_pipe_sized(size)?,
1009 None => std::io::pipe()?,
1010 };
1011 Ok((
1012 PipeSend(PipeSendInner::Native(NativePipeSend {
1013 inner: Arc::new(send),
1014 pending: None,
1015 })),
1016 PipeRecv(PipeRecvInner::Native(NativePipeRecv {
1017 inner: Arc::new(recv),
1018 pending: None,
1019 ready: None,
1020 })),
1021 ))
1022 }
1023}
1024
1025#[cfg(target_os = "linux")]
1029pub(crate) fn set_pipe_buffer_size(fd: std::os::fd::RawFd, size: usize) {
1030 let size = i32::try_from(size).unwrap_or(i32::MAX);
1031 unsafe {
1034 libc::fcntl(fd, libc::F_SETPIPE_SZ, size);
1035 }
1036}
1037
1038#[cfg(all(unix, not(target_os = "linux")))]
1039pub(crate) fn set_pipe_buffer_size(_fd: std::os::fd::RawFd, _size: usize) {}
1040
1041#[cfg(windows)]
1047fn create_pipe_sized(size: usize) -> io::Result<(std::io::PipeReader, std::io::PipeWriter)> {
1048 use std::os::windows::io::FromRawHandle;
1049
1050 use windows_sys::Win32::{
1051 Foundation::HANDLE, Security::SECURITY_ATTRIBUTES, System::Pipes::CreatePipe,
1052 };
1053
1054 let mut read_handle: HANDLE = std::ptr::null_mut();
1055 let mut write_handle: HANDLE = std::ptr::null_mut();
1056 let attrs = SECURITY_ATTRIBUTES {
1057 nLength: size_of::<SECURITY_ATTRIBUTES>() as u32,
1058 lpSecurityDescriptor: std::ptr::null_mut(),
1059 bInheritHandle: 0,
1060 };
1061 let size = u32::try_from(size).unwrap_or(u32::MAX);
1062 let ok = unsafe { CreatePipe(&mut read_handle, &mut write_handle, &attrs, size) };
1065 if ok == 0 {
1066 return Err(io::Error::last_os_error());
1067 }
1068 let reader = unsafe { std::io::PipeReader::from_raw_handle(read_handle as _) };
1071 let writer = unsafe { std::io::PipeWriter::from_raw_handle(write_handle as _) };
1072 Ok((reader, writer))
1073}
1074
1075impl PipeSend {
1076 pub(crate) fn remote(remote: crate::client::RemotePipeSend) -> Self {
1077 Self(PipeSendInner::Remote(remote))
1078 }
1079
1080 pub async fn try_clone(&self) -> Result<Self> {
1082 match &self.0 {
1083 #[cfg(unix)]
1084 PipeSendInner::Native(pipe) => {
1085 let fd = pipe.as_fd().try_clone_to_owned()?;
1086 Ok(Self(PipeSendInner::Native(
1087 tokio::net::unix::pipe::Sender::from_owned_fd_unchecked(fd)?,
1088 )))
1089 }
1090 #[cfg(windows)]
1091 PipeSendInner::Native(NativePipeSend { inner, .. }) => {
1092 Ok(Self(PipeSendInner::Native(NativePipeSend {
1093 inner: Arc::new(inner.try_clone()?),
1094 pending: None,
1095 })))
1096 }
1097 PipeSendInner::Remote(remote) => Ok(Self::remote(remote.try_clone().await?)),
1098 }
1099 }
1100
1101 pub async fn into_stdio(self) -> Result<Stdio> {
1105 match self.0 {
1106 #[cfg(unix)]
1107 PipeSendInner::Native(pipe) => {
1108 let fd: OwnedFd = pipe.into_blocking_fd()?;
1109 Ok(Stdio::from(fd))
1110 }
1111 #[cfg(windows)]
1112 PipeSendInner::Native(NativePipeSend { inner, pending }) => {
1113 if pending.is_some() {
1114 return Err(Error::new(
1115 ErrorKind::ResourceBusy,
1116 "cannot convert PipeSend while an async write is in flight",
1117 ));
1118 }
1119 Ok(Arc::try_unwrap(inner)
1120 .or_else(|inner| inner.try_clone())
1121 .map(Stdio::from)?)
1122 }
1123 PipeSendInner::Remote(_) => Err(Error::new(
1124 ErrorKind::InvalidInput,
1125 "remote stdio cannot be converted to a native handle",
1126 )),
1127 }
1128 }
1129
1130 pub(crate) async fn into_blocking_handle(self) -> io::Result<DefaultHandle> {
1131 match self.0 {
1132 #[cfg(unix)]
1133 PipeSendInner::Native(pipe) => pipe.into_blocking_fd(),
1134 #[cfg(windows)]
1135 PipeSendInner::Native(NativePipeSend { inner, pending }) => {
1136 if pending.is_some() {
1137 return Err(io::Error::other(
1138 "cannot convert PipeSend while an async write is in flight",
1139 ));
1140 }
1141 let pipe = Arc::try_unwrap(inner).or_else(|inner| inner.try_clone())?;
1142 Ok(OwnedHandle::from(pipe))
1143 }
1144 PipeSendInner::Remote(_) => Err(io::Error::new(
1145 io::ErrorKind::InvalidInput,
1146 "remote stdio has no native handle",
1147 )),
1148 }
1149 }
1150}
1151
1152impl PipeRecv {
1153 pub(crate) fn remote(remote: crate::client::RemotePipeRecv) -> Self {
1154 Self(PipeRecvInner::Remote(remote))
1155 }
1156
1157 pub async fn try_clone(&self) -> Result<Self> {
1159 match &self.0 {
1160 #[cfg(unix)]
1161 PipeRecvInner::Native(pipe) => {
1162 let fd = pipe.as_fd().try_clone_to_owned()?;
1163 Ok(Self(PipeRecvInner::Native(
1164 tokio::net::unix::pipe::Receiver::from_owned_fd_unchecked(fd)?,
1165 )))
1166 }
1167 #[cfg(windows)]
1168 PipeRecvInner::Native(NativePipeRecv { inner, .. }) => {
1169 Ok(Self(PipeRecvInner::Native(NativePipeRecv {
1170 inner: Arc::new(inner.try_clone()?),
1171 pending: None,
1172 ready: None,
1173 })))
1174 }
1175 PipeRecvInner::Remote(remote) => Ok(Self::remote(remote.try_clone().await?)),
1176 }
1177 }
1178
1179 pub async fn into_stdio(self) -> Result<Stdio> {
1183 match self.0 {
1184 #[cfg(unix)]
1185 PipeRecvInner::Native(pipe) => {
1186 let fd: OwnedFd = pipe.into_blocking_fd()?;
1187 Ok(Stdio::from(fd))
1188 }
1189 #[cfg(windows)]
1190 PipeRecvInner::Native(NativePipeRecv { inner, pending, .. }) => {
1191 if pending.is_some() {
1192 return Err(Error::new(
1193 ErrorKind::ResourceBusy,
1194 "cannot convert PipeRecv while an async read is in flight",
1195 ));
1196 }
1197 Ok(Arc::try_unwrap(inner)
1198 .or_else(|inner| inner.try_clone())
1199 .map(Stdio::from)?)
1200 }
1201 PipeRecvInner::Remote(_) => Err(Error::new(
1202 ErrorKind::InvalidInput,
1203 "remote stdio cannot be converted to a native handle",
1204 )),
1205 }
1206 }
1207
1208 pub(crate) async fn into_blocking_handle(self) -> io::Result<DefaultHandle> {
1209 match self.0 {
1210 #[cfg(unix)]
1211 PipeRecvInner::Native(pipe) => pipe.into_blocking_fd(),
1212 #[cfg(windows)]
1213 PipeRecvInner::Native(NativePipeRecv { inner, pending, .. }) => {
1214 if pending.is_some() {
1215 return Err(io::Error::other(
1216 "cannot convert PipeRecv while an async read is in flight",
1217 ));
1218 }
1219 let pipe = Arc::try_unwrap(inner).or_else(|inner| inner.try_clone())?;
1220 Ok(OwnedHandle::from(pipe))
1221 }
1222 PipeRecvInner::Remote(_) => Err(io::Error::new(
1223 io::ErrorKind::InvalidInput,
1224 "remote stdio has no native handle",
1225 )),
1226 }
1227 }
1228}
1229
1230impl AsyncWrite for PipeSend {
1231 fn poll_write(
1232 mut self: Pin<&mut Self>,
1233 cx: &mut Context<'_>,
1234 buf: &[u8],
1235 ) -> Poll<io::Result<usize>> {
1236 match &mut self.0 {
1237 PipeSendInner::Native(native) => TokioWrite::poll_write(Pin::new(native), cx, buf),
1238 PipeSendInner::Remote(remote) => Pin::new(remote).poll_write(cx, buf),
1239 }
1240 }
1241
1242 fn poll_write_vectored(
1243 mut self: Pin<&mut Self>,
1244 cx: &mut Context<'_>,
1245 bufs: &[IoSlice<'_>],
1246 ) -> Poll<io::Result<usize>> {
1247 match &mut self.0 {
1248 PipeSendInner::Native(native) => {
1249 TokioWrite::poll_write_vectored(Pin::new(native), cx, bufs)
1250 }
1251 PipeSendInner::Remote(remote) => Pin::new(remote).poll_write_vectored(cx, bufs),
1252 }
1253 }
1254
1255 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1256 match &mut self.0 {
1257 PipeSendInner::Native(native) => TokioWrite::poll_flush(Pin::new(native), cx),
1258 PipeSendInner::Remote(remote) => Pin::new(remote).poll_flush(cx),
1259 }
1260 }
1261
1262 fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1263 match &mut self.0 {
1264 PipeSendInner::Native(native) => TokioWrite::poll_shutdown(Pin::new(native), cx),
1265 PipeSendInner::Remote(remote) => Pin::new(remote).poll_close(cx),
1266 }
1267 }
1268}
1269
1270impl AsyncRead for PipeRecv {
1271 fn poll_read(
1272 mut self: Pin<&mut Self>,
1273 cx: &mut Context<'_>,
1274 buf: &mut [u8],
1275 ) -> Poll<io::Result<usize>> {
1276 match &mut self.0 {
1277 PipeRecvInner::Native(native) => {
1278 let mut buf = ReadBuf::new(buf);
1279 ready!(TokioRead::poll_read(Pin::new(native), cx, &mut buf))?;
1280 Poll::Ready(Ok(buf.filled().len()))
1281 }
1282 PipeRecvInner::Remote(remote) => Pin::new(remote).poll_read(cx, buf),
1283 }
1284 }
1285}
1286
1287#[cfg(windows)]
1288impl TokioWrite for NativePipeSend {
1289 fn poll_write(
1290 mut self: Pin<&mut Self>,
1291 cx: &mut Context<'_>,
1292 buf: &[u8],
1293 ) -> Poll<io::Result<usize>> {
1294 let Self { inner, pending } = &mut *self;
1295 if let Some(task) = pending {
1296 return match Pin::new(task).poll(cx) {
1297 Poll::Pending => Poll::Pending,
1298 Poll::Ready(Ok(result)) => {
1299 *pending = None;
1300 Poll::Ready(result)
1301 }
1302 Poll::Ready(Err(error)) => {
1303 *pending = None;
1304 Poll::Ready(Err(io::Error::other(error)))
1305 }
1306 };
1307 }
1308 let inner = Arc::clone(inner);
1309 let data = buf.to_vec();
1310 *pending = Some(tokio::task::spawn_blocking(move || (&*inner).write(&data)));
1311 self.poll_write(cx, &[])
1312 }
1313 fn poll_write_vectored(
1314 mut self: Pin<&mut Self>,
1315 cx: &mut Context<'_>,
1316 bufs: &[IoSlice<'_>],
1317 ) -> Poll<io::Result<usize>> {
1318 let Self { inner, pending } = &mut *self;
1319 if let Some(task) = pending {
1320 return match Pin::new(task).poll(cx) {
1321 Poll::Pending => Poll::Pending,
1322 Poll::Ready(Ok(result)) => {
1323 *pending = None;
1324 Poll::Ready(result)
1325 }
1326 Poll::Ready(Err(error)) => {
1327 *pending = None;
1328 Poll::Ready(Err(io::Error::other(error)))
1329 }
1330 };
1331 }
1332 let mut data = Vec::new();
1333 for buf in bufs {
1334 data.extend_from_slice(buf);
1335 }
1336 if data.is_empty() {
1337 return Poll::Ready(Ok(0));
1338 }
1339 let inner = Arc::clone(inner);
1340 *pending = Some(tokio::task::spawn_blocking(move || (&*inner).write(&data)));
1341 self.poll_write_vectored(cx, &[])
1342 }
1343 fn is_write_vectored(&self) -> bool {
1344 true
1345 }
1346 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1347 match self.as_mut().poll_write(cx, &[]) {
1348 Poll::Pending => Poll::Pending,
1349 Poll::Ready(Ok(_)) => Poll::Ready(Ok(())),
1350 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
1351 }
1352 }
1353 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1354 self.poll_flush(cx)
1355 }
1356}
1357
1358#[cfg(windows)]
1359impl TokioRead for NativePipeRecv {
1360 fn poll_read(
1361 mut self: Pin<&mut Self>,
1362 cx: &mut Context<'_>,
1363 buf: &mut ReadBuf<'_>,
1364 ) -> Poll<io::Result<()>> {
1365 let Self {
1366 inner,
1367 pending,
1368 ready,
1369 } = &mut *self;
1370 if let Some((data, len)) = ready {
1371 let n = (*len).min(buf.remaining());
1372 buf.put_slice(&data[..n]);
1373 if n == *len {
1374 *ready = None;
1375 } else {
1376 data.drain(..n);
1377 *len -= n;
1378 }
1379 return Poll::Ready(Ok(()));
1380 }
1381 if pending.is_none() {
1382 if buf.remaining() == 0 {
1383 return Poll::Ready(Ok(()));
1384 }
1385 let inner = Arc::clone(inner);
1386 let cap = buf.remaining();
1387 *pending = Some(tokio::task::spawn_blocking(move || {
1388 let mut data = vec![0; cap];
1389 let result = (&*inner).read(&mut data);
1390 (data, result)
1391 }));
1392 }
1393 match Pin::new(pending.as_mut().unwrap()).poll(cx) {
1394 Poll::Pending => Poll::Pending,
1395 Poll::Ready(Ok((data, Ok(len)))) => {
1396 *pending = None;
1397 let n = len.min(buf.remaining());
1398 buf.put_slice(&data[..n]);
1399 if n < len {
1400 *ready = Some((data[n..len].to_vec(), len - n));
1401 }
1402 Poll::Ready(Ok(()))
1403 }
1404 Poll::Ready(Ok((_, Err(error)))) => {
1405 *pending = None;
1406 Poll::Ready(Err(error))
1407 }
1408 Poll::Ready(Err(error)) => {
1409 *pending = None;
1410 Poll::Ready(Err(io::Error::other(error)))
1411 }
1412 }
1413 }
1414}