code.vegaprotocol.io/vega@v0.79.0/datanode/broker/socket_server.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package broker
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"net"
    22  	"strings"
    23  
    24  	"code.vegaprotocol.io/vega/core/events"
    25  	"code.vegaprotocol.io/vega/logging"
    26  
    27  	"github.com/golang/protobuf/proto"
    28  	"go.nanomsg.org/mangos/v3"
    29  	mangosErr "go.nanomsg.org/mangos/v3/errors"
    30  	"go.nanomsg.org/mangos/v3/protocol"
    31  	"go.nanomsg.org/mangos/v3/protocol/pair"
    32  	"golang.org/x/sync/errgroup"
    33  
    34  	_ "go.nanomsg.org/mangos/v3/transport/inproc" // changes behavior of nanomsg
    35  	_ "go.nanomsg.org/mangos/v3/transport/tcp"    // changes behavior of nanomsg
    36  )
    37  
    38  // socketServer receives events from a remote broker.
    39  // This is used by the data node to receive events from a non-validating core node.
    40  type socketServer struct {
    41  	log    *logging.Logger
    42  	config *Config
    43  
    44  	sock protocol.Socket
    45  }
    46  
    47  func pipeEventToString(pe mangos.PipeEvent) string {
    48  	switch pe {
    49  	case mangos.PipeEventAttached:
    50  		return "Attached"
    51  	case mangos.PipeEventDetached:
    52  		return "Detached"
    53  	default:
    54  		return "Attaching"
    55  	}
    56  }
    57  
    58  func newSocketServer(log *logging.Logger, config *Config) (*socketServer, error) {
    59  	sock, err := pair.NewSocket()
    60  	if err != nil {
    61  		return nil, fmt.Errorf("failed to create new socket: %w", err)
    62  	}
    63  
    64  	return &socketServer{
    65  		log:    log.Named("socket-server"),
    66  		config: config,
    67  		sock:   sock,
    68  	}, nil
    69  }
    70  
    71  func (s socketServer) Listen() error {
    72  	addr := fmt.Sprintf(
    73  		"%s://%s",
    74  		strings.ToLower(s.config.SocketConfig.TransportType),
    75  		net.JoinHostPort(s.config.SocketConfig.IP, fmt.Sprintf("%d", s.config.SocketConfig.Port)),
    76  	)
    77  
    78  	listenOptions := map[string]interface{}{mangos.OptionMaxRecvSize: 0}
    79  
    80  	listener, err := s.sock.NewListener(addr, listenOptions)
    81  	if err != nil {
    82  		return fmt.Errorf("failed to make listener %w", err)
    83  	}
    84  
    85  	if err := listener.Listen(); err != nil {
    86  		return fmt.Errorf("failed to listen on %v: %w", addr, err)
    87  	}
    88  
    89  	s.log.Info("Starting broker socket server", logging.String("addr", s.config.SocketConfig.IP),
    90  		logging.Int("port", s.config.SocketConfig.Port))
    91  
    92  	s.sock.SetPipeEventHook(func(pe mangos.PipeEvent, p mangos.Pipe) {
    93  		s.log.Info(
    94  			"New broker connection event",
    95  			logging.String("eventType", pipeEventToString(pe)),
    96  			logging.Uint32("id", p.ID()),
    97  			logging.String("address", p.Address()),
    98  		)
    99  	})
   100  
   101  	return nil
   102  }
   103  
   104  func (s socketServer) Receive(ctx context.Context) (<-chan []byte, <-chan error) {
   105  	outboundCh := make(chan []byte, s.config.SocketServerOutboundBufferSize)
   106  	// channel onto which we push the raw messages from the queue
   107  	inboundCh := make(chan []byte, s.config.SocketServerInboundBufferSize)
   108  	errCh := make(chan error, 1)
   109  
   110  	eg, ctx := errgroup.WithContext(ctx)
   111  
   112  	eg.Go(func() error {
   113  		<-ctx.Done()
   114  		if err := s.close(); err != nil {
   115  			return fmt.Errorf("failed to close socket: %w", err)
   116  		}
   117  		return nil
   118  	})
   119  
   120  	eg.Go(func() error {
   121  		defer close(outboundCh)
   122  
   123  		for msg := range inboundCh {
   124  			// Listen for context cancels, even if we're blocked sending events
   125  			select {
   126  			case outboundCh <- msg:
   127  			case <-ctx.Done():
   128  				return ctx.Err()
   129  			}
   130  		}
   131  
   132  		return nil
   133  	})
   134  
   135  	eg.Go(func() error {
   136  		var recvTimeouts int
   137  		defer close(inboundCh)
   138  		for {
   139  			msg, err := s.sock.Recv()
   140  			if err != nil {
   141  				switch err {
   142  				case mangosErr.ErrRecvTimeout:
   143  					s.log.Warn("Receive socket timeout", logging.Error(err))
   144  					recvTimeouts++
   145  					if recvTimeouts > s.config.SocketConfig.MaxReceiveTimeouts {
   146  						return fmt.Errorf("more then a 3 socket timeouts occurred: %w", err)
   147  					}
   148  				case mangosErr.ErrBadVersion:
   149  					return fmt.Errorf("failed with bad protocol version: %w", err)
   150  				case mangosErr.ErrClosed:
   151  					return nil
   152  				default:
   153  					s.log.Error("Failed to Receive message", logging.Error(err))
   154  					continue
   155  				}
   156  			}
   157  
   158  			inboundCh <- msg
   159  			recvTimeouts = 0
   160  		}
   161  	})
   162  
   163  	go func() {
   164  		defer func() {
   165  			close(errCh)
   166  		}()
   167  
   168  		if err := eg.Wait(); err != nil {
   169  			errCh <- err
   170  		}
   171  	}()
   172  
   173  	return outboundCh, errCh
   174  }
   175  
   176  func (s socketServer) Send(evt events.Event) error {
   177  	msg, err := proto.Marshal(evt.StreamMessage())
   178  	if err != nil {
   179  		return fmt.Errorf("failed to marshal event: %w", err)
   180  	}
   181  
   182  	err = s.sock.Send(msg)
   183  	if err != nil {
   184  		switch err {
   185  		case protocol.ErrClosed:
   186  			return fmt.Errorf("socket is closed: %w", err)
   187  		case protocol.ErrSendTimeout:
   188  			return fmt.Errorf("failed to queue message on socket: %w", err)
   189  		default:
   190  			return fmt.Errorf("failed to send to socket: %w", err)
   191  		}
   192  	}
   193  
   194  	return nil
   195  }
   196  
   197  func (s socketServer) close() error {
   198  	s.log.Info("Closing socket server")
   199  	return s.sock.Close()
   200  }