github.com/Jeffail/benthos/v3@v3.65.0/lib/input/udp_server.go (about) 1 package input 2 3 import ( 4 "bufio" 5 "bytes" 6 "io" 7 "net" 8 "sync/atomic" 9 "time" 10 11 "github.com/Jeffail/benthos/v3/internal/docs" 12 "github.com/Jeffail/benthos/v3/lib/log" 13 "github.com/Jeffail/benthos/v3/lib/message" 14 "github.com/Jeffail/benthos/v3/lib/metrics" 15 "github.com/Jeffail/benthos/v3/lib/types" 16 ) 17 18 //------------------------------------------------------------------------------ 19 20 func init() { 21 Constructors[TypeUDPServer] = TypeSpec{ 22 constructor: fromSimpleConstructor(NewUDPServer), 23 Description: ` 24 Creates a server that receives messages over UDP as a continuous stream of data. 25 Each line is interpretted as an individual message, if the delimiter field is 26 left empty then line feed (\n) is used. 27 28 The field ` + "`max_buffer`" + ` specifies the maximum amount of memory to 29 allocate for buffering lines of data, this must exceed the largest expected 30 message size.`, 31 Status: docs.StatusDeprecated, 32 config: docs.FieldComponent().WithChildren( 33 docs.FieldCommon("address", ""), 34 docs.FieldCommon("max_buffer", ""), 35 docs.FieldCommon("delimiter", ""), 36 ), 37 } 38 } 39 40 //------------------------------------------------------------------------------ 41 42 // UDPServerConfig contains configuration for the UDPServer input type. 43 type UDPServerConfig struct { 44 Address string `json:"address" yaml:"address"` 45 MaxBuffer int `json:"max_buffer" yaml:"max_buffer"` 46 Delim string `json:"delimiter" yaml:"delimiter"` 47 } 48 49 // NewUDPServerConfig creates a new UDPServerConfig with default values. 50 func NewUDPServerConfig() UDPServerConfig { 51 return UDPServerConfig{ 52 Address: "127.0.0.1:0", 53 MaxBuffer: 1000000, 54 Delim: "", 55 } 56 } 57 58 //------------------------------------------------------------------------------ 59 60 // UDPServer is an input type that binds to an address and consumes streams of 61 // messages over UDP. 62 type UDPServer struct { 63 running int32 64 65 conf UDPServerConfig 66 stats metrics.Type 67 log log.Modular 68 69 delim []byte 70 conn net.PacketConn 71 72 transactions chan types.Transaction 73 74 closeChan chan struct{} 75 closedChan chan struct{} 76 } 77 78 // NewUDPServer creates a new UDPServer input type. 79 func NewUDPServer(conf Config, mgr types.Manager, log log.Modular, stats metrics.Type) (Type, error) { 80 pc, err := net.ListenPacket("udp", conf.UDPServer.Address) 81 if err != nil { 82 return nil, err 83 } 84 delim := []byte("\n") 85 if len(conf.UDPServer.Delim) > 0 { 86 delim = []byte(conf.UDPServer.Delim) 87 } 88 t := UDPServer{ 89 running: 1, 90 conf: conf.UDPServer, 91 stats: stats, 92 log: log, 93 94 delim: delim, 95 conn: pc, 96 97 transactions: make(chan types.Transaction), 98 closeChan: make(chan struct{}), 99 closedChan: make(chan struct{}), 100 } 101 102 go t.loop() 103 return &t, nil 104 } 105 106 //------------------------------------------------------------------------------ 107 108 // Addr returns the underlying UDP listeners address. 109 func (t *UDPServer) Addr() net.Addr { 110 return t.conn.LocalAddr() 111 } 112 113 func (t *UDPServer) newScanner(r net.PacketConn) *bufio.Scanner { 114 scanner := bufio.NewScanner(&wrapPacketConn{PacketConn: r}) 115 if t.conf.MaxBuffer != bufio.MaxScanTokenSize { 116 scanner.Buffer([]byte{}, t.conf.MaxBuffer) 117 } 118 119 scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) { 120 if atEOF && len(data) == 0 { 121 return 0, nil, nil 122 } 123 124 if i := bytes.Index(data, t.delim); i >= 0 { 125 // We have a full terminated line. 126 return i + len(t.delim), data[0:i], nil 127 } 128 129 // If we're at EOF, we have a final, non-terminated line. Return it. 130 if atEOF { 131 return len(data), data, nil 132 } 133 134 // Request more data. 135 return 0, nil, nil 136 }) 137 138 return scanner 139 } 140 141 func (t *UDPServer) loop() { 142 var ( 143 mCount = t.stats.GetCounter("count") 144 mRcvd = t.stats.GetCounter("batch.received") 145 mPartsRcvd = t.stats.GetCounter("received") 146 mLatency = t.stats.GetTimer("latency") 147 ) 148 149 defer func() { 150 atomic.StoreInt32(&t.running, 0) 151 152 if t.conn != nil { 153 t.conn.Close() 154 } 155 156 close(t.transactions) 157 close(t.closedChan) 158 }() 159 160 t.log.Infof("Receiving UDP messages from address: %v\n", t.conn.LocalAddr()) 161 162 sendMsg := func(msg types.Message) error { 163 tStarted := time.Now() 164 mPartsRcvd.Incr(int64(msg.Len())) 165 mRcvd.Incr(1) 166 167 resChan := make(chan types.Response) 168 select { 169 case t.transactions <- types.NewTransaction(msg, resChan): 170 case <-t.closeChan: 171 return types.ErrTypeClosed 172 } 173 174 select { 175 case res, open := <-resChan: 176 if !open { 177 return types.ErrTypeClosed 178 } 179 if res != nil { 180 if res.Error() != nil { 181 return res.Error() 182 } 183 } 184 case <-t.closeChan: 185 return types.ErrTypeClosed 186 } 187 mLatency.Timing(time.Since(tStarted).Nanoseconds()) 188 return nil 189 } 190 191 go func() { 192 var msg types.Message 193 msgLoop := func() { 194 for msg != nil { 195 sendErr := sendMsg(msg) 196 if sendErr == nil || sendErr == types.ErrTypeClosed { 197 msg = nil 198 return 199 } 200 t.log.Errorf("Failed to send message: %v\n", sendErr) 201 <-time.After(time.Second) 202 } 203 } 204 for { 205 scanner := t.newScanner(t.conn) 206 for scanner.Scan() { 207 mCount.Incr(1) 208 if len(scanner.Bytes()) == 0 { 209 continue 210 } 211 if msg == nil { 212 msg = message.New(nil) 213 } 214 msg.Append(message.NewPart(scanner.Bytes())) 215 msgLoop() 216 } 217 if msg != nil { 218 msgLoop() 219 } 220 if cerr := scanner.Err(); cerr != nil { 221 if cerr != io.EOF { 222 t.log.Errorf("Connection error due to: %v\n", cerr) 223 } 224 } 225 } 226 }() 227 <-t.closeChan 228 } 229 230 // TransactionChan returns a transactions channel for consuming messages from 231 // this input. 232 func (t *UDPServer) TransactionChan() <-chan types.Transaction { 233 return t.transactions 234 } 235 236 // Connected returns a boolean indicating whether this input is currently 237 // connected to its target. 238 func (t *UDPServer) Connected() bool { 239 return true 240 } 241 242 // CloseAsync shuts down the UDPServer input and stops processing requests. 243 func (t *UDPServer) CloseAsync() { 244 if atomic.CompareAndSwapInt32(&t.running, 1, 0) { 245 close(t.closeChan) 246 } 247 } 248 249 // WaitForClose blocks until the UDPServer input has closed down. 250 func (t *UDPServer) WaitForClose(timeout time.Duration) error { 251 select { 252 case <-t.closedChan: 253 case <-time.After(timeout): 254 return types.ErrTimeout 255 } 256 return nil 257 } 258 259 //------------------------------------------------------------------------------