func (s *Server) Run(ctx context.Context) {
	for {
		if err := s.poll(ctx); err != nil {
			return
		}
	}
}
Run runs the server, blocking until the socket is closed or an error occurs.
package server
import (
	"context"
	"io"
	"log"
	"net"
	"sync"
	"time"
	"github.com/fragglet/ipxbox/ipx"
	"github.com/fragglet/ipxbox/network"
	"github.com/fragglet/ipxbox/network/stats"
)
type Config struct {
	ClientTimeout time.Duration
	KeepaliveTime time.Duration
	Logger *log.Logger
}
type client struct {
	addr            *net.UDPAddr
	node            network.Node
	lastReceiveTime time.Time
	lastSendTime    time.Time
}
type Server struct {
	net              network.Network
	mu               sync.Mutex
	config           *Config
	socket           *net.UDPConn
	clients          map[string]*client
	timeoutCheckTime time.Time
}
var (
	DefaultConfig = &Config{
		ClientTimeout: 10 * time.Minute,
		KeepaliveTime: 5 * time.Second,
	}
	addrPingReply = [6]byte{0x02, 0xff, 0xff, 0xff, 0x00, 0x00}
	_ = (io.Closer)(&Server{})
)
func New(addr string, n network.Network, c *Config) (*Server, error) {
	udp4Addr, err := net.ResolveUDPAddr("udp4", addr)
	if err != nil {
		return nil, err
	}
	socket, err := net.ListenUDP("udp", udp4Addr)
	if err != nil {
		return nil, err
	}
	s := &Server{
		net:              n,
		config:           c,
		socket:           socket,
		clients:          map[string]*client{},
		timeoutCheckTime: time.Now().Add(10e9),
	}
	return s, nil
}
func (s *Server) runClient(ctx context.Context, c *client) {
	for {
		packet, err := c.node.ReadPacket(ctx)
		switch {
		case err == nil:
		case err == io.ErrClosedPipe:
			return
		default:
			s.log("unexpected error reading packet for transmit: %v", err)
			return
		}
		packetBytes, err := packet.MarshalBinary()
		if err != nil {
			s.log("failed to marshal packet: %v", err)
			continue
		}
		s.socket.WriteToUDP(packetBytes, c.addr)
	}
}
func (s *Server) log(format string, args ...interface{}) {
	if s.config.Logger != nil {
		s.config.Logger.Printf(format, args...)
	}
}
func (s *Server) newClient(ctx context.Context, header *ipx.Header, addr *net.UDPAddr) {
	addrStr := addr.String()
	c, ok := s.clients[addrStr]
	if !ok {
		now := time.Now()
		c = &client{
			addr:            addr,
			lastReceiveTime: now,
			node:            s.net.NewNode(),
		}
		s.clients[addrStr] = c
		s.log("new connection from %s, assigned IPX address %s",
			addrStr, network.NodeAddress(c.node))
		go s.runClient(ctx, c)
	}
	reply := &ipx.Header{
		Checksum:     0xffff,
		Length:       30,
		TransControl: 0,
		Dest: ipx.HeaderAddr{
			Network: [4]byte{0, 0, 0, 0},
			Addr:    network.NodeAddress(c.node),
			Socket:  2,
		},
		Src: ipx.HeaderAddr{
			Network: [4]byte{0, 0, 0, 1},
			Addr:    ipx.AddrBroadcast,
			Socket:  2,
		},
	}
	c.lastSendTime = time.Now()
	encodedReply, err := reply.MarshalBinary()
	if err == nil {
		s.socket.WriteToUDP(encodedReply, c.addr)
	}
}
func (s *Server) processPacket(ctx context.Context, packetBytes []byte, addr *net.UDPAddr) {
	packet := &ipx.Packet{}
	if err := packet.UnmarshalBinary(packetBytes); err != nil {
		return
	}
	if packet.Header.IsRegistrationPacket() {
		s.newClient(ctx, &packet.Header, addr)
		return
	}
	srcClient, ok := s.clients[addr.String()]
	if !ok {
		return
	}
	srcClient.lastReceiveTime = time.Now()
	srcClient.node.WritePacket(packet)
}
func (s *Server) sendPing(c *client) {
	header := &ipx.Header{
		Dest: ipx.HeaderAddr{
			Addr:   ipx.AddrBroadcast,
			Socket: 2,
		},
		Src: ipx.HeaderAddr{
			Addr:   addrPingReply,
			Socket: 0,
		},
	}
	c.lastSendTime = time.Now()
	encodedHeader, err := header.MarshalBinary()
	if err == nil {
		s.socket.WriteToUDP(encodedHeader, c.addr)
	}
}
func (s *Server) checkClientTimeouts() time.Time {
	now := time.Now()
	nextCheckTime := now.Add(10 * time.Second)
	for addrStr, c := range s.clients {
		keepaliveTime := c.lastSendTime.Add(s.config.KeepaliveTime)
		if now.After(keepaliveTime) {
			s.sendPing(c)
			keepaliveTime = c.lastSendTime.Add(s.config.KeepaliveTime)
		}
		timeoutTime := c.lastReceiveTime.Add(s.config.ClientTimeout)
		if now.After(timeoutTime) {
			s.log(("client %s (IPX address %s) timed out: " +
				"nothing received since %s. %s"),
				addrStr, network.NodeAddress(c.node),
				c.lastReceiveTime, stats.Summary(c.node))
			delete(s.clients, c.addr.String())
			c.node.Close()
		}
		if keepaliveTime.Before(nextCheckTime) {
			nextCheckTime = keepaliveTime
		}
		if timeoutTime.Before(nextCheckTime) {
			nextCheckTime = timeoutTime
		}
	}
	return nextCheckTime
}
func (s *Server) poll(ctx context.Context) error {
	var buf [1500]byte
	s.socket.SetReadDeadline(s.timeoutCheckTime)
	packetLen, addr, err := s.socket.ReadFromUDP(buf[:])
	if err == nil {
		s.processPacket(ctx, buf[0:packetLen], addr)
	} else if nerr, ok := err.(net.Error); ok && !nerr.Timeout() {
		return err
	}
	if time.Now().After(s.timeoutCheckTime) {
		s.timeoutCheckTime = s.checkClientTimeouts()
	}
	return nil
}