Files
selfcare/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/server.go
2025-03-03 11:40:37 +08:00

192 lines
4.1 KiB
Go

package telnet
import (
"crypto/tls"
"net"
)
// ListenAndServe listens on the TCP network address `addr` and then spawns a call to the ServeTELNET
// method on the `handler` to serve each incoming connection.
//
// For a very simple example:
//
// package main
//
// import (
// "github.com/reiver/go-telnet"
// )
//
// func main() {
//
// //@TODO: In your code, you would probably want to use a different handler.
// var handler telnet.Handler = telnet.EchoHandler
//
// err := telnet.ListenAndServe(":5555", handler)
// if nil != err {
// //@TODO: Handle this error better.
// panic(err)
// }
// }
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
// Serve accepts an incoming TELNET or TELNETS client connection on the net.Listener `listener`.
func Serve(listener net.Listener, handler Handler) error {
server := &Server{Handler: handler}
return server.Serve(listener)
}
// A Server defines parameters of a running TELNET server.
//
// For a simple example:
//
// package main
//
// import (
// "github.com/reiver/go-telnet"
// )
//
// func main() {
//
// var handler telnet.Handler = telnet.EchoHandler
//
// server := &telnet.Server{
// Addr:":5555",
// Handler:handler,
// }
//
// err := server.ListenAndServe()
// if nil != err {
// //@TODO: Handle this error better.
// panic(err)
// }
// }
type Server struct {
Addr string // TCP address to listen on; ":telnet" or ":telnets" if empty (when used with ListenAndServe or ListenAndServeTLS respectively).
Handler Handler // handler to invoke; telnet.EchoServer if nil
TLSConfig *tls.Config // optional TLS configuration; used by ListenAndServeTLS.
Logger Logger
}
// ListenAndServe listens on the TCP network address 'server.Addr' and then spawns a call to the ServeTELNET
// method on the 'server.Handler' to serve each incoming connection.
//
// For a simple example:
//
// package main
//
// import (
// "github.com/reiver/go-telnet"
// )
//
// func main() {
//
// var handler telnet.Handler = telnet.EchoHandler
//
// server := &telnet.Server{
// Addr:":5555",
// Handler:handler,
// }
//
// err := server.ListenAndServe()
// if nil != err {
// //@TODO: Handle this error better.
// panic(err)
// }
// }
func (server *Server) ListenAndServe() error {
addr := server.Addr
if "" == addr {
addr = ":telnet"
}
listener, err := net.Listen("tcp", addr)
if nil != err {
return err
}
return server.Serve(listener)
}
// Serve accepts an incoming TELNET client connection on the net.Listener `listener`.
func (server *Server) Serve(listener net.Listener) error {
defer listener.Close()
logger := server.logger()
handler := server.Handler
if nil == handler {
//@TODO: Should this be a "ShellHandler" instead, that gives a shell-like experience by default
// If this is changd, then need to change the comment in the "type Server struct" definition.
logger.Debug("Defaulted handler to EchoHandler.")
handler = EchoHandler
}
for {
// Wait for a new TELNET client connection.
logger.Debugf("Listening at %q.", listener.Addr())
conn, err := listener.Accept()
if err != nil {
//@TODO: Could try to recover from certain kinds of errors. Maybe waiting a while before trying again.
return err
}
logger.Debugf("Received new connection from %q.", conn.RemoteAddr())
// Handle the new TELNET client connection by spawning
// a new goroutine.
go server.handle(conn, handler)
logger.Debugf("Spawned handler to handle connection from %q.", conn.RemoteAddr())
}
}
func (server *Server) handle(c net.Conn, handler Handler) {
defer c.Close()
logger := server.logger()
defer func(){
if r := recover(); nil != r {
if nil != logger {
logger.Errorf("Recovered from: (%T) %v", r, r)
}
}
}()
var ctx Context = NewContext().InjectLogger(logger)
var w Writer = newDataWriter(c)
var r Reader = newDataReader(c)
handler.ServeTELNET(ctx, w, r)
c.Close()
}
func (server *Server) logger() Logger {
logger := server.Logger
if nil == logger {
logger = internalDiscardLogger{}
}
return logger
}