func (s *Server) Shutdown() {
	if !s.singlePort {
		s.conn.Close()
	}
	q := make(chan struct{})
	s.quit <- q
	<-q
	s.wg.Wait()
}
Shutdown make server stop listening for new requests, allows
server to finish outstanding transfers and stops server.
package tftp
import (
	"fmt"
	"io"
	"net"
	"sync"
	"time"
	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"
)
func NewServer(readHandler func(filename string, rf io.ReaderFrom) error,
	writeHandler func(filename string, wt io.WriterTo) error) *Server {
	s := &Server{
		timeout:           defaultTimeout,
		retries:           defaultRetries,
		runGC:             make(chan []string),
		gcThreshold:       100,
		packetReadTimeout: 100 * time.Millisecond,
		readHandler:       readHandler,
		writeHandler:      writeHandler,
	}
	return s
}
type RequestPacketInfo interface {
	LocalIP() net.IP
}
type Server struct {
	readHandler  func(filename string, rf io.ReaderFrom) error
	writeHandler func(filename string, wt io.WriterTo) error
	hook         Hook
	backoff      backoffFunc
	conn         net.PacketConn
	conn6        *ipv6.PacketConn
	conn4        *ipv4.PacketConn
	quit         chan chan struct{}
	wg           sync.WaitGroup
	timeout      time.Duration
	retries      int
	maxBlockLen  int
	sendAEnable  bool  
	sendAWinSz   uint
	singlePort        bool
	bufPool           sync.Pool
	handlers          map[string]chan []byte
	runGC             chan []string
	gcCollect         chan string
	gcThreshold       int
	packetReadTimeout time.Duration
}
type TransferStats struct {
	RemoteAddr              net.IP
	Filename                string
	Tid                     int
	SenderAnticipateEnabled bool
	Mode                    string
	Opts                    options
	Duration                time.Duration
	DatagramsSent           int
	DatagramsAcked          int
}
type Hook interface {
	OnSuccess(stats TransferStats)
	OnFailure(stats TransferStats, err error)
}
func (s *Server) SetAnticipate(winsz uint) {
	if winsz > 1 {
		s.sendAEnable = true
		s.sendAWinSz = winsz
	} else {
		s.sendAEnable = false
		s.sendAWinSz = 1
	}
}
func (s *Server) SetHook(hook Hook) {
	s.hook = hook
}
func (s *Server) EnableSinglePort() {
	s.singlePort = true
	s.handlers = make(map[string]chan []byte)
	s.gcCollect = make(chan string)
	if s.maxBlockLen == 0 {
		s.maxBlockLen = blockLength
	}
	s.bufPool = sync.Pool{
		New: func() interface{} {
			return make([]byte, s.maxBlockLen+4)
		},
	}
	go s.internalGC()
}
func (s *Server) SetTimeout(t time.Duration) {
	if t <= 0 {
		s.timeout = defaultTimeout
	} else {
		s.timeout = t
	}
}
func (s *Server) SetBlockSize(i int) {
	if i > 512 && i < 65465 {
		s.maxBlockLen = i
	}
}
func (s *Server) SetRetries(count int) {
	if count < 1 {
		s.retries = defaultRetries
	} else {
		s.retries = count
	}
}
func (s *Server) SetBackoff(h backoffFunc) {
	s.backoff = h
}
func (s *Server) ListenAndServe(addr string) error {
	a, err := net.ResolveUDPAddr("udp", addr)
	if err != nil {
		return err
	}
	conn, err := net.ListenUDP("udp", a)
	if err != nil {
		return err
	}
	return s.Serve(conn)
}
func (s *Server) Serve(conn net.PacketConn) error {
	defer conn.Close()
	laddr := conn.LocalAddr()
	host, _, err := net.SplitHostPort(laddr.String())
	if err != nil {
		return err
	}
	s.conn = conn
	addr := net.ParseIP(host)
	if addr == nil {
		return fmt.Errorf("Failed to determine IP class of listening address")
	}
	if conn, ok := conn.(*net.UDPConn); ok {
		if addr.To4() != nil {
			s.conn4 = ipv4.NewPacketConn(conn)
			if err := s.conn4.SetControlMessage(ipv4.FlagDst|ipv4.FlagInterface, true); err != nil {
				s.conn4 = nil
			}
		} else {
			s.conn6 = ipv6.NewPacketConn(conn)
			if err := s.conn6.SetControlMessage(ipv6.FlagDst|ipv6.FlagInterface, true); err != nil {
				s.conn6 = nil
			}
		}
	}
	s.quit = make(chan chan struct{})
	if s.singlePort {
		s.singlePortProcessRequests()
	} else {
		for {
			select {
			case q := <-s.quit:
				q <- struct{}{}
				return nil
			default:
				var err error
				if s.conn4 != nil {
					err = s.processRequest4()
				} else if s.conn6 != nil {
					err = s.processRequest6()
				} else {
					err = s.processRequest()
				}
				if err != nil && s.hook != nil {
					s.hook.OnFailure(TransferStats{
						SenderAnticipateEnabled: s.sendAEnable,
					}, err)
				}
			}
		}
	}
	return nil
}
func (s *Server) processRequest4() error {
	buf := make([]byte, datagramLength)
	cnt, control, srcAddr, err := s.conn4.ReadFrom(buf)
	if err != nil {
		return fmt.Errorf("reading UDP: %v", err)
	}
	maxSz := blockLength
	var localAddr net.IP
	if control != nil {
		localAddr = control.Dst
		if intf, err := net.InterfaceByIndex(control.IfIndex); err == nil {
			maxSz = intf.MTU - 28
		}
	}
	return s.handlePacket(localAddr, srcAddr.(*net.UDPAddr), buf, cnt, maxSz, nil)
}
func (s *Server) processRequest6() error {
	buf := make([]byte, datagramLength)
	cnt, control, srcAddr, err := s.conn6.ReadFrom(buf)
	if err != nil {
		return fmt.Errorf("reading UDP: %v", err)
	}
	maxSz := blockLength
	var localAddr net.IP
	if control != nil {
		localAddr = control.Dst
		if intf, err := net.InterfaceByIndex(control.IfIndex); err == nil {
			maxSz = intf.MTU - 48
		}
	}
	return s.handlePacket(localAddr, srcAddr.(*net.UDPAddr), buf, cnt, maxSz, nil)
}
func (s *Server) processRequest() error {
	buf := make([]byte, datagramLength)
	cnt, srcAddr, err := s.conn.ReadFrom(buf)
	if err != nil {
		return fmt.Errorf("reading UDP: %v", err)
	}
	return s.handlePacket(nil, srcAddr.(*net.UDPAddr), buf, cnt, blockLength, nil)
}