func (t *attachServerSSH) channelMux(in <-chan *ssh.Request, process *os.Process, pty *os.File, detach func()) { defer trace.End(trace.Begin("start attach server channel request handler")) var err error for req := range in { var pendingFn func() ok := true switch req.Type { case msgs.WindowChangeReq: msg := msgs.WindowChangeMsg{} if pty == nil { ok = false log.Errorf("illegal window-change request for non-tty") } else if err = msg.Unmarshal(req.Payload); err != nil { ok = false log.Errorf(err.Error()) } else if err = resizePty(pty.Fd(), &msg); err != nil { ok = false log.Errorf(err.Error()) } case msgs.SignalReq: msg := msgs.SignalMsg{} if err = msg.Unmarshal(req.Payload); err != nil { ok = false log.Errorf(err.Error()) } else { log.Infof("Sending signal %s to container process, pid=%d\n", string(msg.Signal), process.Pid) err = signalProcess(process, msg.Signal) if err != nil { log.Errorf("Failed to dispatch signal to process: %s\n", err) } } default: ok = false err = fmt.Errorf("ssh request type %s is not supported", req.Type) log.Error(err.Error()) } // payload is ignored on channel specific replies. The ok is passed, however. if req.WantReply { req.Reply(ok, nil) } // run any pending work now that a reply has been sent if pendingFn != nil { log.Debug("Invoking pending work") go pendingFn() pendingFn = nil } } detach() }
// Resize resizes the terminal. func (t *attachSSH) Resize(cols, rows, widthpx, heightpx uint32) error { defer trace.End(trace.Begin("")) msg := msgs.WindowChangeMsg{ Columns: cols, Rows: rows, WidthPx: widthpx, HeightPx: heightpx, } ok, err := t.channel.SendRequest(msgs.WindowChangeReq, true, msg.Marshal()) if err == nil && !ok { return fmt.Errorf("unknown error") } if err != nil { return fmt.Errorf("resize error: %s", err) } return nil }
func (t *attachServerSSH) channelMux(in <-chan *ssh.Request, session *tether.SessionConfig, cleanup func()) { defer trace.End(trace.Begin("attach server channel request handler")) // for the actions after we process the request var pendingFn func() // cleanup function passed by the caller defer cleanup() for req := range in { ok := true switch req.Type { case msgs.WindowChangeReq: session.Lock() pty := session.Pty session.Unlock() msg := msgs.WindowChangeMsg{} if pty == nil { ok = false log.Errorf("illegal window-change request for non-tty") } else if err := msg.Unmarshal(req.Payload); err != nil { ok = false log.Errorf(err.Error()) } else if err := resizePty(pty.Fd(), &msg); err != nil { ok = false log.Errorf(err.Error()) } case msgs.CloseStdinReq: // call Close as the pendingFn so that we can send reply back before closing the channel pendingFn = func() { session.Lock() defer session.Unlock() log.Debugf("Closing stdin for %s", session.ID) session.Reader.Close() } default: ok = false err := fmt.Errorf("ssh request type %s is not supported", req.Type) log.Error(err.Error()) } // payload is ignored on channel specific replies. The ok is passed, however. if req.WantReply { log.Debugf("Sending channel request reply %t back", ok) if err := req.Reply(ok, nil); err != nil { log.Warnf("Failed to reply a channel request back") } } // run any pending work now that a reply has been sent if pendingFn != nil { log.Debug("Invoking pending work for channel mux") go pendingFn() pendingFn = nil } } }