func newServerShell(ch *serverChan, prompt string) *ServerTerminal { term := terminal.NewTerminal(ch, prompt) return &ServerTerminal{ Term: term, Channel: ch, } }
func ExampleListen() { // An SSH server is represented by a ServerConfig, which holds // certificate details and handles authentication of ServerConns. config := &ServerConfig{ PasswordCallback: func(conn *ServerConn, user, pass string) bool { return user == "testuser" && pass == "tiger" }, } privateBytes, err := ioutil.ReadFile("id_rsa") if err != nil { panic("Failed to load private key") } private, err := ParsePrivateKey(privateBytes) if err != nil { panic("Failed to parse private key") } config.AddHostKey(private) // Once a ServerConfig has been configured, connections can be // accepted. listener, err := Listen("tcp", "0.0.0.0:2022", config) if err != nil { panic("failed to listen for connection") } sConn, err := listener.Accept() if err != nil { panic("failed to accept incoming connection") } if err := sConn.Handshake(); err != nil { panic("failed to handshake") } // A ServerConn multiplexes several channels, which must // themselves be Accepted. for { // Accept reads from the connection, demultiplexes packets // to their corresponding channels and returns when a new // channel request is seen. Some goroutine must always be // calling Accept; otherwise no messages will be forwarded // to the channels. channel, err := sConn.Accept() if err != nil { panic("error from Accept") } // Channels have a type, depending on the application level // protocol intended. In the case of a shell, the type is // "session" and ServerShell may be used to present a simple // terminal interface. if channel.ChannelType() != "session" { channel.Reject(UnknownChannelType, "unknown channel type") continue } channel.Accept() term := terminal.NewTerminal(channel, "> ") serverTerm := &ServerTerminal{ Term: term, Channel: channel, } go func() { defer channel.Close() for { line, err := serverTerm.ReadLine() if err != nil { break } fmt.Println(line) } }() } }