github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/p2p/connection/connection.go (about)

     1  package connection
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"math"
     7  	"net"
     8  	"runtime/debug"
     9  	"sync/atomic"
    10  	"time"
    11  
    12  	log "github.com/sirupsen/logrus"
    13  	wire "github.com/tendermint/go-wire"
    14  	cmn "github.com/tendermint/tmlibs/common"
    15  	"github.com/tendermint/tmlibs/flowrate"
    16  )
    17  
    18  const (
    19  	packetTypePing           = byte(0x01)
    20  	packetTypePong           = byte(0x02)
    21  	packetTypeMsg            = byte(0x03)
    22  	maxMsgPacketPayloadSize  = 1024
    23  	maxMsgPacketOverheadSize = 10 // It's actually lower but good enough
    24  	maxMsgPacketTotalSize    = maxMsgPacketPayloadSize + maxMsgPacketOverheadSize
    25  
    26  	numBatchMsgPackets = 10
    27  	minReadBufferSize  = 1024
    28  	minWriteBufferSize = 65536
    29  	updateState        = 2 * time.Second
    30  	pingTimeout        = 40 * time.Second
    31  	flushThrottle      = 100 * time.Millisecond
    32  
    33  	defaultSendQueueCapacity   = 1
    34  	defaultSendRate            = int64(512000) // 500KB/s
    35  	defaultRecvBufferCapacity  = 4096
    36  	defaultRecvMessageCapacity = 22020096      // 21MB
    37  	defaultRecvRate            = int64(512000) // 500KB/s
    38  	defaultSendTimeout         = 10 * time.Second
    39  	logModule                  = "p2pConn"
    40  )
    41  
    42  type receiveCbFunc func(chID byte, msgBytes []byte)
    43  type errorCbFunc func(interface{})
    44  
    45  // Messages in channels are chopped into smaller msgPackets for multiplexing.
    46  type msgPacket struct {
    47  	ChannelID byte
    48  	EOF       byte // 1 means message ends here.
    49  	Bytes     []byte
    50  }
    51  
    52  func (p msgPacket) String() string {
    53  	return fmt.Sprintf("MsgPacket{%X:%X T:%X}", p.ChannelID, p.Bytes, p.EOF)
    54  }
    55  
    56  /*
    57  MConnection handles message transmission on multiple abstract communication
    58  `Channel`s.  Each channel has a globally unique byte id.
    59  The byte id and the relative priorities of each `Channel` are configured upon
    60  initialization of the connection.
    61  
    62  There are two methods for sending messages:
    63  	func (m MConnection) Send(chID byte, msg interface{}) bool {}
    64  	func (m MConnection) TrySend(chID byte, msg interface{}) bool {}
    65  
    66  `Send(chID, msg)` is a blocking call that waits until `msg` is successfully queued
    67  for the channel with the given id byte `chID`, or until the request times out.
    68  The message `msg` is serialized using the `tendermint/wire` submodule's
    69  `WriteBinary()` reflection routine.
    70  
    71  `TrySend(chID, msg)` is a nonblocking call that returns false if the channel's
    72  queue is full.
    73  
    74  Inbound message bytes are handled with an onReceive callback function.
    75  */
    76  type MConnection struct {
    77  	cmn.BaseService
    78  
    79  	conn        net.Conn
    80  	bufReader   *bufio.Reader
    81  	bufWriter   *bufio.Writer
    82  	sendMonitor *flowrate.Monitor
    83  	recvMonitor *flowrate.Monitor
    84  	send        chan struct{}
    85  	pong        chan struct{}
    86  	channels    []*channel
    87  	channelsIdx map[byte]*channel
    88  	onReceive   receiveCbFunc
    89  	onError     errorCbFunc
    90  	errored     uint32
    91  	config      *MConnConfig
    92  
    93  	quit         chan struct{}
    94  	flushTimer   *cmn.ThrottleTimer // flush writes as necessary but throttled.
    95  	pingTimer    *time.Ticker       // send pings periodically
    96  	chStatsTimer *time.Ticker       // update channel stats periodically
    97  }
    98  
    99  // MConnConfig is a MConnection configuration.
   100  type MConnConfig struct {
   101  	SendRate int64 `mapstructure:"send_rate"`
   102  	RecvRate int64 `mapstructure:"recv_rate"`
   103  }
   104  
   105  // DefaultMConnConfig returns the default config.
   106  func DefaultMConnConfig() *MConnConfig {
   107  	return &MConnConfig{
   108  		SendRate: defaultSendRate,
   109  		RecvRate: defaultRecvRate,
   110  	}
   111  }
   112  
   113  // NewMConnectionWithConfig wraps net.Conn and creates multiplex connection with a config
   114  func NewMConnectionWithConfig(conn net.Conn, chDescs []*ChannelDescriptor, onReceive receiveCbFunc, onError errorCbFunc, config *MConnConfig) *MConnection {
   115  	mconn := &MConnection{
   116  		conn:        conn,
   117  		bufReader:   bufio.NewReaderSize(conn, minReadBufferSize),
   118  		bufWriter:   bufio.NewWriterSize(conn, minWriteBufferSize),
   119  		sendMonitor: flowrate.New(0, 0),
   120  		recvMonitor: flowrate.New(0, 0),
   121  		send:        make(chan struct{}, 1),
   122  		pong:        make(chan struct{}, 1),
   123  		channelsIdx: map[byte]*channel{},
   124  		channels:    []*channel{},
   125  		onReceive:   onReceive,
   126  		onError:     onError,
   127  		config:      config,
   128  
   129  		pingTimer:    time.NewTicker(pingTimeout),
   130  		chStatsTimer: time.NewTicker(updateState),
   131  	}
   132  
   133  	for _, desc := range chDescs {
   134  		descCopy := *desc // copy the desc else unsafe access across connections
   135  		channel := newChannel(mconn, &descCopy)
   136  		mconn.channelsIdx[channel.id] = channel
   137  		mconn.channels = append(mconn.channels, channel)
   138  	}
   139  	mconn.BaseService = *cmn.NewBaseService(nil, "MConnection", mconn)
   140  	return mconn
   141  }
   142  
   143  // OnStart implements BaseService
   144  func (c *MConnection) OnStart() error {
   145  	c.BaseService.OnStart()
   146  	c.quit = make(chan struct{})
   147  	c.flushTimer = cmn.NewThrottleTimer("flush", flushThrottle)
   148  	go c.sendRoutine()
   149  	go c.recvRoutine()
   150  	return nil
   151  }
   152  
   153  // OnStop implements BaseService
   154  func (c *MConnection) OnStop() {
   155  	c.BaseService.OnStop()
   156  	c.flushTimer.Stop()
   157  	c.pingTimer.Stop()
   158  	c.chStatsTimer.Stop()
   159  	if c.quit != nil {
   160  		close(c.quit)
   161  	}
   162  	c.conn.Close()
   163  	// We can't close pong safely here because recvRoutine may write to it after we've
   164  	// stopped. Though it doesn't need to get closed at all, we close it @ recvRoutine.
   165  }
   166  
   167  // CanSend returns true if you can send more data onto the chID, false otherwise
   168  func (c *MConnection) CanSend(chID byte) bool {
   169  	if !c.IsRunning() {
   170  		return false
   171  	}
   172  
   173  	channel, ok := c.channelsIdx[chID]
   174  	if !ok {
   175  		return false
   176  	}
   177  	return channel.canSend()
   178  }
   179  
   180  // Send will queues a message to be sent to channel(blocking).
   181  func (c *MConnection) Send(chID byte, msg interface{}) bool {
   182  	if !c.IsRunning() {
   183  		return false
   184  	}
   185  
   186  	channel, ok := c.channelsIdx[chID]
   187  	if !ok {
   188  		log.WithFields(log.Fields{"module": logModule, "chID": chID}).Error("cannot send bytes due to unknown channel")
   189  		return false
   190  	}
   191  
   192  	if !channel.sendBytes(wire.BinaryBytes(msg)) {
   193  		log.WithFields(log.Fields{"module": logModule, "chID": chID, "conn": c, "msg": msg}).Error("MConnection send failed")
   194  		return false
   195  	}
   196  
   197  	select {
   198  	case c.send <- struct{}{}:
   199  	default:
   200  	}
   201  	return true
   202  }
   203  
   204  // TrafficStatus return the in and out traffic status
   205  func (c *MConnection) TrafficStatus() (*flowrate.Status, *flowrate.Status) {
   206  	sentStatus := c.sendMonitor.Status()
   207  	receivedStatus := c.recvMonitor.Status()
   208  	return &sentStatus, &receivedStatus
   209  }
   210  
   211  // TrySend queues a message to be sent to channel(Nonblocking).
   212  func (c *MConnection) TrySend(chID byte, msg interface{}) bool {
   213  	if !c.IsRunning() {
   214  		return false
   215  	}
   216  
   217  	channel, ok := c.channelsIdx[chID]
   218  	if !ok {
   219  		log.WithFields(log.Fields{"module": logModule, "chID": chID}).Error("cannot send bytes due to unknown channel")
   220  		return false
   221  	}
   222  
   223  	ok = channel.trySendBytes(wire.BinaryBytes(msg))
   224  	if ok {
   225  		select {
   226  		case c.send <- struct{}{}:
   227  		default:
   228  		}
   229  	}
   230  	return ok
   231  }
   232  
   233  func (c *MConnection) String() string {
   234  	return fmt.Sprintf("MConn{%v}", c.conn.RemoteAddr())
   235  }
   236  
   237  func (c *MConnection) flush() {
   238  	if err := c.bufWriter.Flush(); err != nil {
   239  		log.WithFields(log.Fields{"module": logModule, "error": err}).Warn("MConnection flush failed")
   240  	}
   241  }
   242  
   243  // Catch panics, usually caused by remote disconnects.
   244  func (c *MConnection) _recover() {
   245  	if r := recover(); r != nil {
   246  		stack := debug.Stack()
   247  		c.stopForError(fmt.Sprintf("Error: %v\nStack: %s", r, stack))
   248  	}
   249  }
   250  
   251  // recvRoutine reads msgPackets and reconstructs the message using the channels' "recving" buffer.
   252  // After a whole message has been assembled, it's pushed to onReceive().
   253  // Blocks depending on how the connection is throttled.
   254  func (c *MConnection) recvRoutine() {
   255  	defer c._recover()
   256  	defer close(c.pong)
   257  
   258  	for {
   259  		// Block until .recvMonitor says we can read.
   260  		c.recvMonitor.Limit(maxMsgPacketTotalSize, atomic.LoadInt64(&c.config.RecvRate), true)
   261  
   262  		// Read packet type
   263  		var n int
   264  		var err error
   265  		pktType := wire.ReadByte(c.bufReader, &n, &err)
   266  		c.recvMonitor.Update(int(n))
   267  		if err != nil {
   268  			if c.IsRunning() {
   269  				log.WithFields(log.Fields{"module": logModule, "conn": c, "error": err}).Warn("Connection failed @ recvRoutine (reading byte)")
   270  				c.conn.Close()
   271  				c.stopForError(err)
   272  			}
   273  			return
   274  		}
   275  
   276  		// Read more depending on packet type.
   277  		switch pktType {
   278  		case packetTypePing:
   279  			log.WithFields(log.Fields{"module": logModule, "conn": c}).Debug("receive Ping")
   280  			select {
   281  			case c.pong <- struct{}{}:
   282  			default:
   283  			}
   284  
   285  		case packetTypePong:
   286  			log.WithFields(log.Fields{"module": logModule, "conn": c}).Debug("receive Pong")
   287  
   288  		case packetTypeMsg:
   289  			pkt, n, err := msgPacket{}, int(0), error(nil)
   290  			wire.ReadBinaryPtr(&pkt, c.bufReader, maxMsgPacketTotalSize, &n, &err)
   291  			c.recvMonitor.Update(int(n))
   292  			if err != nil {
   293  				if c.IsRunning() {
   294  					log.WithFields(log.Fields{"module": logModule, "conn": c, "error": err}).Error("failed on recvRoutine")
   295  					c.stopForError(err)
   296  				}
   297  				return
   298  			}
   299  
   300  			channel, ok := c.channelsIdx[pkt.ChannelID]
   301  			if !ok || channel == nil {
   302  				cmn.PanicQ(cmn.Fmt("Unknown channel %X", pkt.ChannelID))
   303  			}
   304  
   305  			msgBytes, err := channel.recvMsgPacket(pkt)
   306  			if err != nil {
   307  				if c.IsRunning() {
   308  					log.WithFields(log.Fields{"module": logModule, "conn": c, "error": err}).Error("failed on recvRoutine")
   309  					c.stopForError(err)
   310  				}
   311  				return
   312  			}
   313  
   314  			if msgBytes != nil {
   315  				c.onReceive(pkt.ChannelID, msgBytes)
   316  			}
   317  
   318  		default:
   319  			cmn.PanicSanity(cmn.Fmt("Unknown message type %X", pktType))
   320  		}
   321  	}
   322  }
   323  
   324  // Returns true if messages from channels were exhausted.
   325  func (c *MConnection) sendMsgPacket() bool {
   326  	var leastRatio float32 = math.MaxFloat32
   327  	var leastChannel *channel
   328  	for _, channel := range c.channels {
   329  		if !channel.isSendPending() {
   330  			continue
   331  		}
   332  		if ratio := float32(channel.recentlySent) / float32(channel.priority); ratio < leastRatio {
   333  			leastRatio = ratio
   334  			leastChannel = channel
   335  		}
   336  	}
   337  	if leastChannel == nil {
   338  		return true
   339  	}
   340  
   341  	n, err := leastChannel.writeMsgPacketTo(c.bufWriter)
   342  	if err != nil {
   343  		log.WithFields(log.Fields{"module": logModule, "error": err}).Error("failed to write msgPacket")
   344  		c.stopForError(err)
   345  		return true
   346  	}
   347  	c.sendMonitor.Update(int(n))
   348  	c.flushTimer.Set()
   349  	return false
   350  }
   351  
   352  // sendRoutine polls for packets to send from channels.
   353  func (c *MConnection) sendRoutine() {
   354  	defer c._recover()
   355  
   356  	for {
   357  		var n int
   358  		var err error
   359  		select {
   360  		case <-c.flushTimer.Ch:
   361  			c.flush()
   362  		case <-c.chStatsTimer.C:
   363  			for _, channel := range c.channels {
   364  				channel.updateStats()
   365  			}
   366  		case <-c.pingTimer.C:
   367  			log.WithFields(log.Fields{"module": logModule, "conn": c}).Debug("send Ping")
   368  			wire.WriteByte(packetTypePing, c.bufWriter, &n, &err)
   369  			c.sendMonitor.Update(int(n))
   370  			c.flush()
   371  		case <-c.pong:
   372  			log.WithFields(log.Fields{"module": logModule, "conn": c}).Debug("send Pong")
   373  			wire.WriteByte(packetTypePong, c.bufWriter, &n, &err)
   374  			c.sendMonitor.Update(int(n))
   375  			c.flush()
   376  		case <-c.quit:
   377  			return
   378  		case <-c.send:
   379  			if eof := c.sendSomeMsgPackets(); !eof {
   380  				select {
   381  				case c.send <- struct{}{}:
   382  				default:
   383  				}
   384  			}
   385  		}
   386  
   387  		if !c.IsRunning() {
   388  			return
   389  		}
   390  		if err != nil {
   391  			log.WithFields(log.Fields{"module": logModule, "conn": c, "error": err}).Warn("Connection failed @ sendRoutine")
   392  			c.stopForError(err)
   393  			return
   394  		}
   395  	}
   396  }
   397  
   398  // Returns true if messages from channels were exhausted.
   399  func (c *MConnection) sendSomeMsgPackets() bool {
   400  	// Block until .sendMonitor says we can write.
   401  	// Once we're ready we send more than we asked for,
   402  	// but amortized it should even out.
   403  	c.sendMonitor.Limit(maxMsgPacketTotalSize, atomic.LoadInt64(&c.config.SendRate), true)
   404  	for i := 0; i < numBatchMsgPackets; i++ {
   405  		if c.sendMsgPacket() {
   406  			return true
   407  		}
   408  	}
   409  	return false
   410  }
   411  
   412  func (c *MConnection) stopForError(r interface{}) {
   413  	c.Stop()
   414  	if atomic.CompareAndSwapUint32(&c.errored, 0, 1) && c.onError != nil {
   415  		c.onError(r)
   416  	}
   417  }