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() }
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 } } }