func (s *session) start(ch ssh.Channel, ctx *ctx) error {
	// create a new "party" (connected client)
	p := newParty(s, ch, ctx)

	// allocate a terminal or take the one previously allocated via a
	// seaprate "allocate TTY" SSH request
	if ctx.getTerm() != nil {
		s.term = ctx.getTerm()
		ctx.setTerm(nil)
	} else {
		var err error
		if s.term, err = newTerminal(); err != nil {
			ctx.Infof("handleShell failed to create term: %v", err)
			return trace.Wrap(err)
		}
	}
	// prepare environment & Launch shell:
	cmd, err := prepInteractiveCommand(ctx)
	if err != nil {
		return trace.Wrap(err)
	}
	if err := s.term.run(cmd); err != nil {
		ctx.Errorf("shell command failed: %v", err)
		return trace.ConvertSystemError(err)
	}
	s.addParty(p)

	// emit "new session created" event:
	s.registry.srv.EmitAuditEvent(events.SessionStartEvent, events.EventFields{
		events.SessionEventID:  string(s.id),
		events.SessionServerID: ctx.srv.ID(),
		events.EventLogin:      ctx.login,
		events.EventUser:       ctx.teleportUser,
		events.LocalAddr:       ctx.conn.LocalAddr().String(),
		events.RemoteAddr:      ctx.conn.RemoteAddr().String(),
		events.TerminalSize:    s.term.params.Serialize(),
	})

	// start recording this session
	auditLog := s.registry.srv.alog
	if auditLog != nil {
		s.writer.addWriter("session-recorder",
			newSessionRecorder(auditLog, s.id),
			true)
	}

	// start asynchronous loop of synchronizing session state with
	// the session server (terminal size and activity)
	go s.pollAndSync()

	// Pipe session to shell and visa-versa capturing input and output
	s.term.Add(1)
	go func() {
		// notify terminal about a copy process going on
		defer s.term.Add(-1)
		io.Copy(s.writer, s.term.pty)
		log.Infof("session.io.copy() stopped")
	}()

	// wait for the shell to complete:
	go func() {
		result, err := collectStatus(cmd, cmd.Wait())
		if result != nil {
			s.registry.broadcastResult(s.id, *result)
		}
		if err != nil {
			log.Errorf("shell exited with error: %v", err)
		} else {
			// no error? this means the command exited cleanly: no need
			// for this session to "linger" after this.
			s.SetLingerTTL(time.Duration(0))
		}
	}()

	// wait for the session to end before the shell, kill the shell
	go func() {
		<-s.closeC
		if cmd.Process != nil {
			if err := cmd.Process.Kill(); err != nil {
				log.Error(err)
			}
		}
	}()
	return nil
}
// start starts a new interactive process (or a shell) in the current session
start starts a new interactive process (or a shell) in the current session
// start starts a new interactive process ( or a shell ) in the current session
func (s *session) start(ch ssh.Channel, ctx *ctx) error {
	p := newParty(s, ch, ctx)
	if ctx.getTerm() != nil {
		s.term = ctx.getTerm()
		ctx.setTerm(nil)
	} else {
		var err error
		if s.term, err = newTerminal(); err != nil {
			ctx.Infof("handleShell failed to create term: %v", err)
			return trace.Wrap(err)
		}
	}
	cmd, err := prepInteractiveCommand(ctx)
	if err != nil {
		return trace.Wrap(err)
	}
	if err := s.term.run(cmd); err != nil {
		ctx.Errorf("shell command failed: %v", err)
		return trace.ConvertSystemError(err)
	}
	s.addParty(p)
	s.registry.srv.EmitAuditEvent(events.SessionStartEvent, events.EventFields{
		events.SessionEventID:  string(s.id),
		events.SessionServerID: ctx.srv.ID(),
		events.EventLogin:      ctx.login,
		events.EventUser:       ctx.teleportUser,
		events.LocalAddr:       ctx.conn.LocalAddr().String(),
		events.RemoteAddr:      ctx.conn.RemoteAddr().String(),
		events.TerminalSize:    s.term.params.Serialize(),
	})
	auditLog := s.registry.srv.alog
	if auditLog != nil {
		s.writer.addWriter("session-recorder",
			newSessionRecorder(auditLog, s.id),
			true)
	}
	go s.pollAndSync()
	s.term.Add(1)
	go func() {
		defer s.term.Add(-1)
		io.Copy(s.writer, s.term.pty)
		log.Infof("session.io.copy() stopped")
	}()
	go func() {
		result, err := collectStatus(cmd, cmd.Wait())
		if result != nil {
			s.registry.broadcastResult(s.id, *result)
		}
		if err != nil {
			log.Errorf("shell exited with error: %v", err)
		} else {
			s.SetLingerTTL(time.Duration(0))
		}
	}()
	go func() {
		<-s.closeC
		if cmd.Process != nil {
			if err := cmd.Process.Kill(); err != nil {
				log.Error(err)
			}
		}
	}()
	return nil
}
func ( s * session ) start ( ch ssh . Channel , ctx * ctx ) error { p := newParty ( s , ch , ctx ) if ctx . getTerm ( ) != nil { s . term = ctx . getTerm ( ) ctx . setTerm ( nil ) } else { var err error if s . term , err = newTerminal ( ) ; err != nil { ctx . Infof ( " " , err ) return trace . Wrap ( err ) } } cmd , err := prepInteractiveCommand ( ctx ) if err != nil { return trace . Wrap ( err ) } if err := s . term . run ( cmd ) ; err != nil { ctx . Errorf ( " " , err ) return trace . ConvertSystemError ( err ) } s . addParty ( p ) s . registry . srv . EmitAuditEvent ( events . SessionStartEvent , events . EventFields { events . SessionEventID : string ( s . id ) , events . SessionServerID : ctx . srv . ID ( ) , events . EventLogin : ctx . login , events . EventUser : ctx . teleportUser , events . LocalAddr : ctx . conn . LocalAddr ( ) . String ( ) , events . RemoteAddr : ctx . conn . RemoteAddr ( ) . String ( ) , events . TerminalSize : s . term . params . Serialize ( ) , } ) auditLog := s . registry . srv . alog if auditLog != nil { s . writer . addWriter ( " " , newSessionRecorder ( auditLog , s . id ) , true ) } go s . pollAndSync ( ) s . term . Add ( 1 ) go func ( ) { defer s . term . Add ( - 1 ) io . Copy ( s . writer , s . term . pty ) log . Infof ( " " ) } ( ) go func ( ) { result , err := collectStatus ( cmd , cmd . Wait ( ) ) if result != nil { s . registry . broadcastResult ( s . id , * result ) } if err != nil { log . Errorf ( " " , err ) } else { s . SetLingerTTL ( time . Duration ( 0 ) ) } } ( ) go func ( ) { <- s . closeC if cmd . Process != nil { if err := cmd . Process . Kill ( ) ; err != nil { log . Error ( err ) } } } ( ) return nil }
start starts a new interactive process (or a shell) in the current session
start starts a new interactive process ( or a shell ) in the current session
// create a new "party" (connected client) // allocate a terminal or take the one previously allocated via a // seaprate "allocate TTY" SSH request // prepare environment & Launch shell: // emit "new session created" event: // start recording this session // start asynchronous loop of synchronizing session state with // the session server (terminal size and activity) // Pipe session to shell and visa-versa capturing input and output // notify terminal about a copy process going on // wait for the shell to complete: // no error? this means the command exited cleanly: no need // for this session to "linger" after this. // wait for the session to end before the shell, kill the shell