add docs and example for DNS frame read/write decorators
This commit is contained in:
parent
e0f83dee9a
commit
e148c23156
40
server.go
40
server.go
|
@ -198,15 +198,23 @@ func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
|
|||
DefaultServeMux.HandleFunc(pattern, handler)
|
||||
}
|
||||
|
||||
// Writer writes DNS data frames; each call to Write should send an entire frame.
|
||||
type Writer interface {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
// Reader reads DNS data frames; each call to ReadTCP or ReadUDP should return an entire frame.
|
||||
type Reader interface {
|
||||
// ReadTCP reads a data frame from a TCP connection. Implementations may alter
|
||||
// connection properties, for example the read-deadline.
|
||||
ReadTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error)
|
||||
// ReadUDP reads a data frame from a UDP connection. Implementations may alter
|
||||
// connection properties, for example the read-deadline.
|
||||
ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error)
|
||||
}
|
||||
|
||||
// defaultReader is an adapter for the Server struct that implements the Reader interface
|
||||
// using the readTCP and readUDP func of the embedded Server.
|
||||
type defaultReader struct {
|
||||
*Server
|
||||
}
|
||||
|
@ -219,9 +227,13 @@ func (dr *defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]by
|
|||
return dr.readUDP(conn, timeout)
|
||||
}
|
||||
|
||||
type ReaderBuilder func(Reader) Reader
|
||||
// DecorateReader is a decorator hook for extending or supplanting the functionality of a Reader.
|
||||
// Implementations should never return a nil Reader.
|
||||
type DecorateReader func(Reader) Reader
|
||||
|
||||
type WriterBuilder func(Writer) Writer
|
||||
// DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer.
|
||||
// Implementations should never return a nil Writer.
|
||||
type DecorateWriter func(Writer) Writer
|
||||
|
||||
// A Server defines parameters for running an DNS server.
|
||||
type Server struct {
|
||||
|
@ -251,10 +263,10 @@ type Server struct {
|
|||
Unsafe bool
|
||||
// If NotifyStartedFunc is set is is called, once the server has started listening.
|
||||
NotifyStartedFunc func()
|
||||
// ReaderBuilder is optional, allows customization of the process that reads DNS frames
|
||||
ReaderBuilder ReaderBuilder
|
||||
// WriterBuilder is optional, allows customization of the process that writes DNS frames
|
||||
WriterBuilder WriterBuilder
|
||||
// DecorateReader is optional, allows customization of the process that reads DNS frames.
|
||||
DecorateReader DecorateReader
|
||||
// DecorateWriter is optional, allows customization of the process that writes DNS frames.
|
||||
DecorateWriter DecorateWriter
|
||||
|
||||
// For graceful shutdown.
|
||||
stopUDP chan bool
|
||||
|
@ -413,8 +425,8 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
|
|||
}
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.ReaderBuilder != nil {
|
||||
reader = srv.ReaderBuilder(reader)
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
|
||||
handler := srv.Handler
|
||||
|
@ -453,8 +465,8 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
|||
}
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.ReaderBuilder != nil {
|
||||
reader = srv.ReaderBuilder(reader)
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
|
||||
handler := srv.Handler
|
||||
|
@ -482,8 +494,8 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
|||
// Serve a new connection.
|
||||
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t *net.TCPConn) {
|
||||
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
|
||||
if srv.WriterBuilder != nil {
|
||||
w.writer = srv.WriterBuilder(w)
|
||||
if srv.DecorateWriter != nil {
|
||||
w.writer = srv.DecorateWriter(w)
|
||||
} else {
|
||||
w.writer = w
|
||||
}
|
||||
|
@ -499,8 +511,8 @@ func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *Ses
|
|||
}()
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.ReaderBuilder != nil {
|
||||
reader = srv.ReaderBuilder(reader)
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
Redo:
|
||||
req := new(Msg)
|
||||
|
|
|
@ -397,3 +397,54 @@ func TestShutdownUDP(t *testing.T) {
|
|||
t.Errorf("Could not shutdown test UDP server, %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type ExampleFrameLengthWriter struct {
|
||||
Writer
|
||||
}
|
||||
|
||||
func (e *ExampleFrameLengthWriter) Write(m []byte) (int, error) {
|
||||
fmt.Println("writing DNS data frame of length", len(m))
|
||||
return e.Writer.Write(m)
|
||||
}
|
||||
|
||||
func ExampleDecorateWriter() {
|
||||
// instrument DNS data frame writing
|
||||
wf := DecorateWriter(func(w Writer) Writer {
|
||||
return &ExampleFrameLengthWriter{w}
|
||||
})
|
||||
|
||||
// simple UDP server
|
||||
pc, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
server := &Server{
|
||||
PacketConn: pc,
|
||||
DecorateWriter: wf,
|
||||
}
|
||||
|
||||
waitLock := sync.Mutex{}
|
||||
waitLock.Lock()
|
||||
server.NotifyStartedFunc = waitLock.Unlock
|
||||
defer server.Shutdown()
|
||||
|
||||
go func() {
|
||||
server.ActivateAndServe()
|
||||
pc.Close()
|
||||
}()
|
||||
|
||||
waitLock.Lock()
|
||||
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
|
||||
c := new(Client)
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeTXT)
|
||||
_, _, err = c.Exchange(m, pc.LocalAddr().String())
|
||||
if err != nil {
|
||||
fmt.Println("failed to exchange", err.Error())
|
||||
return
|
||||
}
|
||||
// Output: writing DNS data frame of length 56
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue