97 lines
2.3 KiB
Go
97 lines
2.3 KiB
Go
package syslogserver
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
log "github.com/sirupsen/logrus"
|
|
"gopkg.in/tomb.v2"
|
|
)
|
|
|
|
type SyslogServer struct {
|
|
listenAddr string
|
|
port int
|
|
channel chan SyslogMessage
|
|
udpConn *net.UDPConn
|
|
Logger *log.Entry
|
|
MaxMessageLen int
|
|
}
|
|
|
|
type SyslogMessage struct {
|
|
Message []byte
|
|
Client string
|
|
}
|
|
|
|
func (s *SyslogServer) Listen(listenAddr string, port int) error {
|
|
|
|
s.listenAddr = listenAddr
|
|
s.port = port
|
|
udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", s.listenAddr, s.port))
|
|
if err != nil {
|
|
return errors.Wrapf(err, "could not resolve addr %s", s.listenAddr)
|
|
}
|
|
udpConn, err := net.ListenUDP("udp", udpAddr)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "could not listen on port %d", s.port)
|
|
}
|
|
s.Logger.Debugf("listening on %s:%d", s.listenAddr, s.port)
|
|
s.udpConn = udpConn
|
|
err = s.udpConn.SetReadBuffer(s.MaxMessageLen) // FIXME probably
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not set readbuffer on UDP socket")
|
|
}
|
|
err = s.udpConn.SetReadDeadline(time.Now().UTC().Add(100 * time.Millisecond))
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not set read deadline on UDP socket")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *SyslogServer) SetChannel(c chan SyslogMessage) {
|
|
s.channel = c
|
|
}
|
|
|
|
func (s *SyslogServer) StartServer() *tomb.Tomb {
|
|
t := tomb.Tomb{}
|
|
|
|
t.Go(func() error {
|
|
for {
|
|
select {
|
|
case <-t.Dying():
|
|
s.Logger.Info("Syslog server tomb is dying")
|
|
err := s.KillServer()
|
|
return err
|
|
default:
|
|
//RFC3164 says 1024 bytes max
|
|
//RFC5424 says 480 bytes minimum, and should support up to 2048 bytes
|
|
b := make([]byte, s.MaxMessageLen)
|
|
n, addr, err := s.udpConn.ReadFrom(b)
|
|
if err != nil && !strings.Contains(err.Error(), "i/o timeout") {
|
|
s.Logger.Errorf("error while reading from socket : %s", err)
|
|
s.udpConn.Close()
|
|
return err
|
|
}
|
|
if err == nil {
|
|
s.channel <- SyslogMessage{Message: b[:n], Client: strings.Split(addr.String(), ":")[0]}
|
|
}
|
|
err = s.udpConn.SetReadDeadline(time.Now().UTC().Add(100 * time.Millisecond))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
})
|
|
return &t
|
|
}
|
|
|
|
func (s *SyslogServer) KillServer() error {
|
|
err := s.udpConn.Close()
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not close UDP connection")
|
|
}
|
|
close(s.channel)
|
|
return nil
|
|
}
|