1package terminal 2 3import ( 4 "fmt" 5 "io" 6) 7 8type FileDescriptorProxy struct { 9 StopCh chan error 10} 11 12// stoppers is the number of goroutines that may attempt to call Stop() 13func NewFileDescriptorProxy(stoppers int) *FileDescriptorProxy { 14 return &FileDescriptorProxy{ 15 StopCh: make(chan error, stoppers+2), // each proxy() call is a stopper 16 } 17} 18 19func (p *FileDescriptorProxy) GetStopCh() chan error { 20 return p.StopCh 21} 22 23func (p *FileDescriptorProxy) Serve(upstream, downstream io.ReadWriter, upstreamAddr, downstreamAddr string) error { 24 // This signals the upstream terminal to kill the exec'd process 25 defer upstream.Write(eot) 26 27 go p.proxy(upstream, downstream, upstreamAddr, downstreamAddr) 28 go p.proxy(downstream, upstream, downstreamAddr, upstreamAddr) 29 30 err := <-p.StopCh 31 return err 32} 33 34func (p *FileDescriptorProxy) proxy(to, from io.ReadWriter, toAddr, fromAddr string) { 35 _, err := io.Copy(to, from) 36 if err != nil { 37 p.StopCh <- fmt.Errorf("copying from %s to %s: %s", fromAddr, toAddr, err) 38 } 39} 40