99 lines
2.2 KiB
Go
99 lines
2.2 KiB
Go
package udp
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"time"
|
|
|
|
"src.dualinventive.com/go/lib/dilog"
|
|
)
|
|
|
|
//DefaultUDPWriteTimeoutSeconds is the default time a udp write operation will block
|
|
const DefaultUDPWriteTimeoutSeconds = 1
|
|
|
|
//DefaultUDPBufferSize is the default buffer size a udp read operation
|
|
const DefaultUDPBufferSize = 4096
|
|
|
|
//ErrNilLogger is returned when no logger is provided
|
|
var ErrNilLogger = errors.New("logger must not be nil")
|
|
|
|
//ErrNilHandler is return when no handler is provided
|
|
var ErrNilHandler = errors.New("handler must not be nil")
|
|
|
|
//Listener listens to udp and routes them to its handler
|
|
type Listener struct {
|
|
log dilog.Logger
|
|
pc net.PacketConn
|
|
buffer []byte
|
|
handler PacketHandler
|
|
}
|
|
|
|
//PacketHandler is able to process UDP packets
|
|
type PacketHandler func([]byte)
|
|
|
|
//NewListener returns a new UDP listener
|
|
func NewListener(
|
|
log dilog.Logger,
|
|
addr string,
|
|
bufferSize int,
|
|
writeDeadline int,
|
|
h PacketHandler,
|
|
) (*Listener, error) {
|
|
if log == nil {
|
|
return nil, ErrNilLogger
|
|
}
|
|
if h == nil {
|
|
return nil, ErrNilHandler
|
|
}
|
|
if addr == "" {
|
|
log.Warning("udp port not configured, using random port")
|
|
}
|
|
if bufferSize == 0 {
|
|
bufferSize = DefaultUDPBufferSize
|
|
log.Warning("udp buffer size not configured, defaulting to 1064 bytes")
|
|
}
|
|
if writeDeadline == 0 {
|
|
writeDeadline = DefaultUDPWriteTimeoutSeconds
|
|
log.Warning("udp write timeout not configured, defaulting to 2 seconds")
|
|
}
|
|
|
|
pc, err := net.ListenPacket("udp", addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
deadline := time.Now().Add(time.Second * time.Duration(writeDeadline))
|
|
err = pc.SetWriteDeadline(deadline)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
buffer := make([]byte, bufferSize)
|
|
|
|
return &Listener{
|
|
log: log,
|
|
pc: pc,
|
|
buffer: buffer,
|
|
handler: h,
|
|
}, nil
|
|
}
|
|
|
|
//ListenAndServe starts the active listening on udp. This call is blocking.
|
|
func (l *Listener) ListenAndServe() error {
|
|
|
|
for {
|
|
n, _, err := l.pc.ReadFrom(l.buffer)
|
|
if err != nil {
|
|
l.log.WithError(err).Warning("error reading udp packet")
|
|
continue
|
|
}
|
|
|
|
go l.handler(l.buffer[:n])
|
|
}
|
|
}
|
|
|
|
//LocalAddr returns the local udp address on which is listened.
|
|
func (l *Listener) LocalAddr() string {
|
|
return l.pc.LocalAddr().String()
|
|
}
|