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 }