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  //------------------------------------------------------------------------------