Godeps changes for kube-dns
This commit is contained in:
311
vendor/github.com/miekg/dns/server.go
generated
vendored
311
vendor/github.com/miekg/dns/server.go
generated
vendored
@@ -4,12 +4,17 @@ package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Maximum number of TCP queries before we close the socket.
|
||||
const maxTCPQueries = 128
|
||||
|
||||
// Handler is implemented by any value that implements ServeDNS.
|
||||
type Handler interface {
|
||||
ServeDNS(w ResponseWriter, r *Msg)
|
||||
}
|
||||
@@ -43,9 +48,10 @@ type response struct {
|
||||
tsigRequestMAC string
|
||||
tsigSecret map[string]string // the tsig secrets
|
||||
udp *net.UDPConn // i/o connection if UDP was used
|
||||
tcp *net.TCPConn // i/o connection if TCP was used
|
||||
udpSession *sessionUDP // oob data to get egress interface right
|
||||
tcp net.Conn // i/o connection if TCP was used
|
||||
udpSession *SessionUDP // oob data to get egress interface right
|
||||
remoteAddr net.Addr // address of the client
|
||||
writer Writer // writer to output the raw DNS bits
|
||||
}
|
||||
|
||||
// ServeMux is an DNS request multiplexer. It matches the
|
||||
@@ -72,12 +78,12 @@ var DefaultServeMux = NewServeMux()
|
||||
// Handler object that calls f.
|
||||
type HandlerFunc func(ResponseWriter, *Msg)
|
||||
|
||||
// ServerDNS calls f(w, r)
|
||||
// ServeDNS calls f(w, r).
|
||||
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
|
||||
f(w, r)
|
||||
}
|
||||
|
||||
// FailedHandler returns a HandlerFunc that returns SERVFAIL for every request it gets.
|
||||
// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets.
|
||||
func HandleFailed(w ResponseWriter, r *Msg) {
|
||||
m := new(Msg)
|
||||
m.SetRcode(r, RcodeServerFailure)
|
||||
@@ -87,13 +93,35 @@ func HandleFailed(w ResponseWriter, r *Msg) {
|
||||
|
||||
func failedHandler() Handler { return HandlerFunc(HandleFailed) }
|
||||
|
||||
// ListenAndServe Starts a server on addresss and network speficied. Invoke handler
|
||||
// ListenAndServe Starts a server on address and network specified Invoke handler
|
||||
// for incoming queries.
|
||||
func ListenAndServe(addr string, network string, handler Handler) error {
|
||||
server := &Server{Addr: addr, Net: network, Handler: handler}
|
||||
return server.ListenAndServe()
|
||||
}
|
||||
|
||||
// ListenAndServeTLS acts like http.ListenAndServeTLS, more information in
|
||||
// http://golang.org/pkg/net/http/#ListenAndServeTLS
|
||||
func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config := tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
|
||||
server := &Server{
|
||||
Addr: addr,
|
||||
Net: "tcp-tls",
|
||||
TLSConfig: &config,
|
||||
Handler: handler,
|
||||
}
|
||||
|
||||
return server.ListenAndServe()
|
||||
}
|
||||
|
||||
// ActivateAndServe activates a server with a listener from systemd,
|
||||
// l and p should not both be non-nil.
|
||||
// If both l and p are not nil only p will be used.
|
||||
@@ -121,10 +149,9 @@ func (mux *ServeMux) match(q string, t uint16) Handler {
|
||||
if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
|
||||
if t != TypeDS {
|
||||
return h
|
||||
} else {
|
||||
// Continue for DS to see if we have a parent too, if so delegeate to the parent
|
||||
handler = h
|
||||
}
|
||||
// Continue for DS to see if we have a parent too, if so delegeate to the parent
|
||||
handler = h
|
||||
}
|
||||
off, end = NextLabel(q, off)
|
||||
if end {
|
||||
@@ -148,7 +175,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
|
||||
mux.m.Unlock()
|
||||
}
|
||||
|
||||
// Handle adds a handler to the ServeMux for pattern.
|
||||
// HandleFunc adds a handler function to the ServeMux for pattern.
|
||||
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
|
||||
mux.Handle(pattern, HandlerFunc(handler))
|
||||
}
|
||||
@@ -158,9 +185,9 @@ func (mux *ServeMux) HandleRemove(pattern string) {
|
||||
if pattern == "" {
|
||||
panic("dns: invalid pattern " + pattern)
|
||||
}
|
||||
// don't need a mutex here, because deleting is OK, even if the
|
||||
// entry is note there.
|
||||
mux.m.Lock()
|
||||
delete(mux.z, Fqdn(pattern))
|
||||
mux.m.Unlock()
|
||||
}
|
||||
|
||||
// ServeDNS dispatches the request to the handler whose
|
||||
@@ -197,14 +224,53 @@ func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
|
||||
DefaultServeMux.HandleFunc(pattern, handler)
|
||||
}
|
||||
|
||||
// Writer writes raw DNS messages; each call to Write should send an entire message.
|
||||
type Writer interface {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
// Reader reads raw DNS messages; each call to ReadTCP or ReadUDP should return an entire message.
|
||||
type Reader interface {
|
||||
// ReadTCP reads a raw message from a TCP connection. Implementations may alter
|
||||
// connection properties, for example the read-deadline.
|
||||
ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error)
|
||||
// ReadUDP reads a raw message 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
|
||||
}
|
||||
|
||||
func (dr *defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
|
||||
return dr.readTCP(conn, timeout)
|
||||
}
|
||||
|
||||
func (dr *defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
|
||||
return dr.readUDP(conn, timeout)
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
// 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 {
|
||||
// Address to listen on, ":dns" if empty.
|
||||
Addr string
|
||||
// if "tcp" it will invoke a TCP listener, otherwise an UDP one.
|
||||
// if "tcp" or "tcp-tls" (DNS over TLS) it will invoke a TCP listener, otherwise an UDP one
|
||||
Net string
|
||||
// TCP Listener to use, this is to aid in systemd's socket activation.
|
||||
Listener net.Listener
|
||||
// TLS connection configuration
|
||||
TLSConfig *tls.Config
|
||||
// UDP "Listener" to use, this is to aid in systemd's socket activation.
|
||||
PacketConn net.PacketConn
|
||||
// Handler to invoke, dns.DefaultServeMux if nil.
|
||||
@@ -221,31 +287,30 @@ type Server struct {
|
||||
// Secret(s) for Tsig map[<zonename>]<base64 secret>.
|
||||
TsigSecret map[string]string
|
||||
// Unsafe instructs the server to disregard any sanity checks and directly hand the message to
|
||||
// the handler. It will specfically not check if the query has the QR bit not set.
|
||||
// the handler. It will specifically not check if the query has the QR bit not set.
|
||||
Unsafe bool
|
||||
// If NotifyStartedFunc is set is is called, once the server has started listening.
|
||||
// If NotifyStartedFunc is set it is called once the server has started listening.
|
||||
NotifyStartedFunc func()
|
||||
// DecorateReader is optional, allows customization of the process that reads raw DNS messages.
|
||||
DecorateReader DecorateReader
|
||||
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
|
||||
DecorateWriter DecorateWriter
|
||||
|
||||
// For graceful shutdown.
|
||||
stopUDP chan bool
|
||||
stopTCP chan bool
|
||||
wgUDP sync.WaitGroup
|
||||
wgTCP sync.WaitGroup
|
||||
// Graceful shutdown handling
|
||||
|
||||
// make start/shutdown not racy
|
||||
lock sync.Mutex
|
||||
inFlight sync.WaitGroup
|
||||
|
||||
lock sync.RWMutex
|
||||
started bool
|
||||
}
|
||||
|
||||
// ListenAndServe starts a nameserver on the configured address in *Server.
|
||||
func (srv *Server) ListenAndServe() error {
|
||||
srv.lock.Lock()
|
||||
defer srv.lock.Unlock()
|
||||
if srv.started {
|
||||
return &Error{err: "server already started"}
|
||||
}
|
||||
srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
addr := srv.Addr
|
||||
if addr == "" {
|
||||
addr = ":domain"
|
||||
@@ -263,7 +328,30 @@ func (srv *Server) ListenAndServe() error {
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
return srv.serveTCP(l)
|
||||
srv.Listener = l
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e = srv.serveTCP(l)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
case "tcp-tls", "tcp4-tls", "tcp6-tls":
|
||||
network := "tcp"
|
||||
if srv.Net == "tcp4-tls" {
|
||||
network = "tcp4"
|
||||
} else if srv.Net == "tcp6" {
|
||||
network = "tcp6"
|
||||
}
|
||||
|
||||
l, e := tls.Listen(network, addr, srv.TLSConfig)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
srv.Listener = l
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e = srv.serveTCP(l)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
case "udp", "udp4", "udp6":
|
||||
a, e := net.ResolveUDPAddr(srv.Net, addr)
|
||||
if e != nil {
|
||||
@@ -276,7 +364,12 @@ func (srv *Server) ListenAndServe() error {
|
||||
if e := setUDPSocketOptions(l); e != nil {
|
||||
return e
|
||||
}
|
||||
return srv.serveUDP(l)
|
||||
srv.PacketConn = l
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e = srv.serveUDP(l)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
}
|
||||
return &Error{err: "bad network"}
|
||||
}
|
||||
@@ -285,71 +378,62 @@ func (srv *Server) ListenAndServe() error {
|
||||
// configured in *Server. Its main use is to start a server from systemd.
|
||||
func (srv *Server) ActivateAndServe() error {
|
||||
srv.lock.Lock()
|
||||
defer srv.lock.Unlock()
|
||||
if srv.started {
|
||||
return &Error{err: "server already started"}
|
||||
}
|
||||
srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
if srv.PacketConn != nil {
|
||||
pConn := srv.PacketConn
|
||||
l := srv.Listener
|
||||
if pConn != nil {
|
||||
if srv.UDPSize == 0 {
|
||||
srv.UDPSize = MinMsgSize
|
||||
}
|
||||
if t, ok := srv.PacketConn.(*net.UDPConn); ok {
|
||||
if t, ok := pConn.(*net.UDPConn); ok {
|
||||
if e := setUDPSocketOptions(t); e != nil {
|
||||
return e
|
||||
}
|
||||
return srv.serveUDP(t)
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e := srv.serveUDP(t)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
}
|
||||
}
|
||||
if srv.Listener != nil {
|
||||
if t, ok := srv.Listener.(*net.TCPListener); ok {
|
||||
return srv.serveTCP(t)
|
||||
}
|
||||
if l != nil {
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e := srv.serveTCP(l)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
}
|
||||
return &Error{err: "bad listeners"}
|
||||
}
|
||||
|
||||
// Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and
|
||||
// ActivateAndServe will return. All in progress queries are completed before the server
|
||||
// is taken down. If the Shutdown is taking longer than the reading timeout and error
|
||||
// is taken down. If the Shutdown is taking longer than the reading timeout an error
|
||||
// is returned.
|
||||
func (srv *Server) Shutdown() error {
|
||||
srv.lock.Lock()
|
||||
if !srv.started {
|
||||
srv.lock.Unlock()
|
||||
return &Error{err: "server not started"}
|
||||
}
|
||||
srv.started = false
|
||||
srv.lock.Unlock()
|
||||
net, addr := srv.Net, srv.Addr
|
||||
switch {
|
||||
case srv.Listener != nil:
|
||||
a := srv.Listener.Addr()
|
||||
net, addr = a.Network(), a.String()
|
||||
case srv.PacketConn != nil:
|
||||
a := srv.PacketConn.LocalAddr()
|
||||
net, addr = a.Network(), a.String()
|
||||
|
||||
if srv.PacketConn != nil {
|
||||
srv.PacketConn.Close()
|
||||
}
|
||||
if srv.Listener != nil {
|
||||
srv.Listener.Close()
|
||||
}
|
||||
|
||||
fin := make(chan bool)
|
||||
switch net {
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
go func() {
|
||||
srv.stopTCP <- true
|
||||
srv.wgTCP.Wait()
|
||||
fin <- true
|
||||
}()
|
||||
|
||||
case "udp", "udp4", "udp6":
|
||||
go func() {
|
||||
srv.stopUDP <- true
|
||||
srv.wgUDP.Wait()
|
||||
fin <- true
|
||||
}()
|
||||
}
|
||||
|
||||
c := &Client{Net: net}
|
||||
go c.Exchange(new(Msg), addr) // extra query to help ReadXXX loop to pass
|
||||
go func() {
|
||||
srv.inFlight.Wait()
|
||||
fin <- true
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(srv.getReadTimeout()):
|
||||
@@ -369,14 +453,19 @@ func (srv *Server) getReadTimeout() time.Duration {
|
||||
}
|
||||
|
||||
// serveTCP starts a TCP listener for the server.
|
||||
// Each request is handled in a seperate goroutine.
|
||||
func (srv *Server) serveTCP(l *net.TCPListener) error {
|
||||
// Each request is handled in a separate goroutine.
|
||||
func (srv *Server) serveTCP(l net.Listener) error {
|
||||
defer l.Close()
|
||||
|
||||
if srv.NotifyStartedFunc != nil {
|
||||
srv.NotifyStartedFunc()
|
||||
}
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
|
||||
handler := srv.Handler
|
||||
if handler == nil {
|
||||
handler = DefaultServeMux
|
||||
@@ -384,27 +473,30 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
|
||||
rtimeout := srv.getReadTimeout()
|
||||
// deadline is not used here
|
||||
for {
|
||||
rw, e := l.AcceptTCP()
|
||||
rw, e := l.Accept()
|
||||
if e != nil {
|
||||
continue
|
||||
if neterr, ok := e.(net.Error); ok && neterr.Temporary() {
|
||||
continue
|
||||
}
|
||||
return e
|
||||
}
|
||||
m, e := srv.readTCP(rw, rtimeout)
|
||||
select {
|
||||
case <-srv.stopTCP:
|
||||
m, e := reader.ReadTCP(rw, rtimeout)
|
||||
srv.lock.RLock()
|
||||
if !srv.started {
|
||||
srv.lock.RUnlock()
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
srv.lock.RUnlock()
|
||||
if e != nil {
|
||||
continue
|
||||
}
|
||||
srv.wgTCP.Add(1)
|
||||
srv.inFlight.Add(1)
|
||||
go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
|
||||
}
|
||||
panic("dns: not reached")
|
||||
}
|
||||
|
||||
// serveUDP starts a UDP listener for the server.
|
||||
// Each request is handled in a seperate goroutine.
|
||||
// Each request is handled in a separate goroutine.
|
||||
func (srv *Server) serveUDP(l *net.UDPConn) error {
|
||||
defer l.Close()
|
||||
|
||||
@@ -412,6 +504,11 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
||||
srv.NotifyStartedFunc()
|
||||
}
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
|
||||
handler := srv.Handler
|
||||
if handler == nil {
|
||||
handler = DefaultServeMux
|
||||
@@ -419,35 +516,39 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
||||
rtimeout := srv.getReadTimeout()
|
||||
// deadline is not used here
|
||||
for {
|
||||
m, s, e := srv.readUDP(l, rtimeout)
|
||||
select {
|
||||
case <-srv.stopUDP:
|
||||
m, s, e := reader.ReadUDP(l, rtimeout)
|
||||
srv.lock.RLock()
|
||||
if !srv.started {
|
||||
srv.lock.RUnlock()
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
srv.lock.RUnlock()
|
||||
if e != nil {
|
||||
continue
|
||||
}
|
||||
srv.wgUDP.Add(1)
|
||||
srv.inFlight.Add(1)
|
||||
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
|
||||
}
|
||||
panic("dns: not reached")
|
||||
}
|
||||
|
||||
// Serve a new connection.
|
||||
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *sessionUDP, t *net.TCPConn) {
|
||||
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t net.Conn) {
|
||||
defer srv.inFlight.Done()
|
||||
|
||||
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
|
||||
q := 0
|
||||
defer func() {
|
||||
if u != nil {
|
||||
srv.wgUDP.Done()
|
||||
}
|
||||
if t != nil {
|
||||
srv.wgTCP.Done()
|
||||
}
|
||||
}()
|
||||
if srv.DecorateWriter != nil {
|
||||
w.writer = srv.DecorateWriter(w)
|
||||
} else {
|
||||
w.writer = w
|
||||
}
|
||||
|
||||
q := 0 // counter for the amount of TCP queries we get
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
Redo:
|
||||
// Ideally we want use isMsg here before we allocate memory to actually parse the packet.
|
||||
req := new(Msg)
|
||||
err := req.Unpack(m)
|
||||
if err != nil { // Send a FormatError back
|
||||
@@ -475,6 +576,15 @@ Redo:
|
||||
h.ServeDNS(w, req) // Writes back to the client
|
||||
|
||||
Exit:
|
||||
if w.tcp == nil {
|
||||
return
|
||||
}
|
||||
// TODO(miek): make this number configurable?
|
||||
if q > maxTCPQueries { // close socket after this many queries
|
||||
w.Close()
|
||||
return
|
||||
}
|
||||
|
||||
if w.hijacked {
|
||||
return // client calls Close()
|
||||
}
|
||||
@@ -486,21 +596,16 @@ Exit:
|
||||
if srv.IdleTimeout != nil {
|
||||
idleTimeout = srv.IdleTimeout()
|
||||
}
|
||||
m, e := srv.readTCP(w.tcp, idleTimeout)
|
||||
m, e := reader.ReadTCP(w.tcp, idleTimeout)
|
||||
if e == nil {
|
||||
q++
|
||||
// TODO(miek): make this number configurable?
|
||||
if q > 128 { // close socket after this many queries
|
||||
w.Close()
|
||||
return
|
||||
}
|
||||
goto Redo
|
||||
}
|
||||
w.Close()
|
||||
return
|
||||
}
|
||||
|
||||
func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error) {
|
||||
func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
|
||||
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||
l := make([]byte, 2)
|
||||
n, err := conn.Read(l)
|
||||
@@ -535,10 +640,10 @@ func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, er
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *sessionUDP, error) {
|
||||
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
|
||||
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||
m := make([]byte, srv.UDPSize)
|
||||
n, s, e := readFromSessionUDP(conn, m)
|
||||
n, s, e := ReadFromSessionUDP(conn, m)
|
||||
if e != nil || n == 0 {
|
||||
if e != nil {
|
||||
return nil, nil, e
|
||||
@@ -558,7 +663,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
_, err = w.writer.Write(data)
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -566,7 +671,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
_, err = w.writer.Write(data)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -574,7 +679,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
|
||||
func (w *response) Write(m []byte) (int, error) {
|
||||
switch {
|
||||
case w.udp != nil:
|
||||
n, err := writeToSessionUDP(w.udp, m, w.udpSession)
|
||||
n, err := WriteToSessionUDP(w.udp, m, w.udpSession)
|
||||
return n, err
|
||||
case w.tcp != nil:
|
||||
lm := len(m)
|
||||
|
Reference in New Issue
Block a user