src.dualinventive.com/go/nbiot-interface/internal/udp/udp.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()
}