github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/network/core.go (about)

     1  package network
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"encoding/binary"
     7  	"encoding/hex"
     8  	"errors"
     9  	"fmt"
    10  	"net"
    11  	"strings"
    12  	"sync"
    13  	"sync/atomic"
    14  	"time"
    15  
    16  	"github.com/piotrnar/gocoin/client/common"
    17  	"github.com/piotrnar/gocoin/client/network/peersdb"
    18  	"github.com/piotrnar/gocoin/lib/btc"
    19  	"github.com/piotrnar/gocoin/lib/others/sys"
    20  )
    21  
    22  const (
    23  	AskAddrsEvery      = (5 * time.Minute)
    24  	MaxAddrsPerMessage = 500
    25  	SendBufSize        = 16 * 1024 * 1024 // If you'd have this much in the send buffer, disconnect the peer
    26  	SendBufMask        = SendBufSize - 1
    27  
    28  	GetHeadersTimeout = 2 * time.Minute  // Timeout to receive headers
    29  	VersionMsgTimeout = 20 * time.Second // Timeout to receive the version message after connecting
    30  	TCPDialTimeout    = 20 * time.Second // If it does not connect within this time, assume it dead
    31  	NoDataTimeout     = 5 * time.Minute  // If no data received within this time, disconnect
    32  
    33  	MIN_PROTO_VERSION = 209
    34  
    35  	HammeringMinReconnect    = 20 * time.Minute // If any incoming peer reconnects in below this time, ban it
    36  	HammeringMaxAllowedCount = 5                // If reconnecting more than this many times within the time above, ban the IP
    37  	HammeringExpirePeriod    = time.Minute      // Expite Hammering history interval
    38  
    39  	ExpireCachedAfter = 20 * time.Minute /*If a block stays in the cache for that long, drop it*/
    40  
    41  	MAX_PEERS_BLOCKS_IN_PROGRESS = 500
    42  	MAX_BLOCKS_FORWARD_CNT       = 5000 // Never ask for a block higher than current top + this value
    43  	MAX_GETDATA_FORWARD          = 2e6  // Download up to 2MB forward (or one block)
    44  
    45  	MAINTANENCE_PERIOD = time.Minute
    46  
    47  	MAX_INV_HISTORY = 500
    48  
    49  	TxsCounterPeriod      = 6 * time.Second // how long for one tick
    50  	TxsCounterBufLen      = 60              // how many ticks
    51  	OnlineImmunityMinutes = int(TxsCounterBufLen * TxsCounterPeriod / time.Minute)
    52  
    53  	PeerTickPeriod  = 100 * time.Millisecond // run the peer's tick not more often than this
    54  	InvsFlushPeriod = 10 * time.Millisecond  // send all the pending invs to the peer not more often than this
    55  
    56  	MAX_GETMP_TXS = 1e6
    57  )
    58  
    59  var (
    60  	Mutex_net                   sync.Mutex
    61  	OpenCons                    map[uint64]*OneConnection = make(map[uint64]*OneConnection)
    62  	InConsActive, OutConsActive uint32
    63  	LastConnId                  uint32
    64  	nonce                       [8]byte
    65  
    66  	// Hammering protection (peers that keep re-connecting) map IPv4 => UnixTime
    67  	HammeringMutex       sync.Mutex
    68  	RecentlyDisconencted map[[4]byte]*RecentlyDisconenctedType = make(map[[4]byte]*RecentlyDisconenctedType)
    69  )
    70  
    71  type RecentlyDisconenctedType struct {
    72  	time.Time
    73  	Count uint
    74  	Why   string
    75  }
    76  
    77  type NetworkNodeStruct struct {
    78  	Version       uint32
    79  	Services      uint64
    80  	Timestamp     uint64
    81  	Height        uint32
    82  	Agent         string
    83  	DoNotRelayTxs bool
    84  	ReportedIp4   uint32
    85  	SendHeaders   bool
    86  	Nonce         [8]byte
    87  
    88  	// BIP152:
    89  	SendCmpctVer  uint64
    90  	HighBandwidth bool
    91  }
    92  
    93  type ConnectionStatus struct {
    94  	Incomming                bool
    95  	ConnectedAt              time.Time
    96  	VersionReceived          bool
    97  	LastBtsRcvd, LastBtsSent uint32
    98  	LastCmdRcvd, LastCmdSent string
    99  	LastDataGot              time.Time // if we have no data for some time, we abort this conenction
   100  	Ticks                    uint64
   101  	OurGetAddrDone           bool // Whether we shoudl issue another "getaddr"
   102  
   103  	AllHeadersReceived      bool // keep sending getheaders until this is not set
   104  	LastHeadersEmpty        bool
   105  	TotalNewHeadersCount    int
   106  	GetHeadersInProgress    bool
   107  	GetHeadersTimeOutAt     time.Time
   108  	GetHeadersSentAtPingCnt uint64
   109  	LastHeadersHeightAsk    uint32
   110  	GetBlocksDataNow        bool
   111  
   112  	LastSent       time.Time
   113  	MaxSentBufSize int
   114  
   115  	PingHistory    [PingHistoryLength]int
   116  	PingHistoryIdx int
   117  	InvsRecieved   uint64
   118  
   119  	BytesReceived, BytesSent uint64
   120  	Counters                 map[string]uint64
   121  
   122  	GetAddrDone bool
   123  	MinFeeSPKB  int64 // BIP 133
   124  
   125  	TxsReceived int // During last hour
   126  
   127  	IsSpecial bool // Special connections get more debgs and are not being automatically dropped
   128  	IsGocoin  bool
   129  	Debug     bool
   130  
   131  	Authorized bool
   132  	AuthMsgGot uint
   133  	AuthAckGot bool
   134  
   135  	LastMinFeePerKByte uint64
   136  
   137  	PingSentCnt   uint64
   138  	BlocksExpired uint64
   139  
   140  	NewAddrsRcvd uint64
   141  	AddrMsgsRcvd uint64
   142  
   143  	ChainSynchronized bool // Initiated by "auth" or "autack" message (gocoin specific commmands)
   144  }
   145  
   146  type ConnInfo struct {
   147  	ID     uint32
   148  	PeerIp string
   149  
   150  	NetworkNodeStruct
   151  	ConnectionStatus
   152  
   153  	BytesToSend      int
   154  	BlocksInProgress int
   155  	InvsToSend       int
   156  	AveragePing      int
   157  	InvsDone         int
   158  	BlocksReceived   int
   159  	GetMPInProgress  bool
   160  
   161  	LocalAddr, RemoteAddr string
   162  
   163  	// This one is only set inside webui's hnadler (for sorted connections)
   164  	HasImmunity bool
   165  }
   166  
   167  type OneConnection struct {
   168  	// Source of this IP:
   169  	*peersdb.PeerAddr
   170  	ConnID uint32
   171  
   172  	sync.Mutex // protects concurent access to any fields inside this structure
   173  
   174  	broken           bool // flag that the conenction has been broken / shall be disconnected
   175  	dead             bool // If set the alive time in PeersDB will ne moved back
   176  	why_disconnected string
   177  	banit            bool // Ban this client after disconnecting
   178  	ban_reason       string
   179  	misbehave        int // When it reaches 1000, ban it
   180  
   181  	net.Conn
   182  
   183  	// TCP connection data:
   184  	X ConnectionStatus
   185  
   186  	Node NetworkNodeStruct // Data from the version message
   187  
   188  	// Messages reception state machine:
   189  	recv struct {
   190  		hdr     [24]byte
   191  		hdr_len int
   192  		pl_len  uint32 // length taken from the message header
   193  		cmd     string
   194  		dat     []byte
   195  		datlen  uint32
   196  	}
   197  	LastMsgTime        time.Time
   198  	unfinished_getdata *bytes.Buffer
   199  
   200  	InvDone struct {
   201  		Map     map[uint64]uint32
   202  		History []uint64
   203  		Idx     int
   204  	}
   205  
   206  	// Message sending state machine:
   207  	sendBuf                  [SendBufSize]byte
   208  	SendBufProd, SendBufCons int
   209  
   210  	// Statistics:
   211  	PendingInvs []*[36]byte // List of pending INV to send and the mutex protecting access to it
   212  	sendInvsNow sys.SyncBool
   213  
   214  	GetBlockInProgress map[BIDX]*oneBlockDl
   215  
   216  	// Ping stats
   217  	LastPingSent   time.Time
   218  	PingInProgress []byte
   219  	lastSec        int64
   220  
   221  	counters map[string]uint64
   222  
   223  	blocksreceived  []time.Time
   224  	nextMaintanence time.Time
   225  	nextGetData     time.Time
   226  	keepBlocksOver  int
   227  
   228  	// we need these three below to count txs received only during last hour
   229  	txsCur int
   230  	txsCha chan int
   231  	txsNxt time.Time
   232  
   233  	writing_thread_done sync.WaitGroup
   234  	writing_thread_push chan bool
   235  
   236  	GetMP chan bool
   237  }
   238  
   239  type BIDX [btc.Uint256IdxLen]byte
   240  
   241  type oneBlockDl struct {
   242  	hash          *btc.Uint256
   243  	start         time.Time
   244  	col           *CmpctBlockCollector
   245  	SentAtPingCnt uint64
   246  }
   247  
   248  type BCmsg struct {
   249  	cmd string
   250  	pl  []byte
   251  }
   252  
   253  func NewConnection(ad *peersdb.PeerAddr) (c *OneConnection) {
   254  	c = new(OneConnection)
   255  	c.PeerAddr = ad
   256  	c.GetBlockInProgress = make(map[BIDX]*oneBlockDl)
   257  	c.ConnID = atomic.AddUint32(&LastConnId, 1)
   258  	c.counters = make(map[string]uint64)
   259  	c.InvDone.Map = make(map[uint64]uint32, MAX_INV_HISTORY)
   260  	c.GetMP = make(chan bool, 1)
   261  	return
   262  }
   263  
   264  func (v *OneConnection) cntLockInc(name string) {
   265  	if !common.NoCounters.Get() {
   266  		v.Mutex.Lock()
   267  		v.counters[name]++
   268  		v.Mutex.Unlock()
   269  	}
   270  }
   271  
   272  func (v *OneConnection) cntInc(name string) {
   273  	if !common.NoCounters.Get() {
   274  		v.counters[name]++
   275  	}
   276  }
   277  
   278  func (v *OneConnection) cntAdd(name string, val uint64) {
   279  	if !common.NoCounters.Get() {
   280  		v.counters[name] += val
   281  	}
   282  }
   283  
   284  // MutexSetBool does a mutex protected assignment of val to addr.
   285  func (v *OneConnection) MutexSetBool(addr *bool, val bool) {
   286  	v.Mutex.Lock()
   287  	*addr = val
   288  	v.Mutex.Unlock()
   289  }
   290  
   291  // MutexGetBool does a mutex protected read of the value of addr and returns it.
   292  func (v *OneConnection) MutexGetBool(addr *bool) (val bool) {
   293  	v.Mutex.Lock()
   294  	val = *addr
   295  	v.Mutex.Unlock()
   296  	return
   297  }
   298  
   299  // call it with locked mutex!
   300  func (v *OneConnection) BytesToSent() int {
   301  	if v.SendBufProd >= v.SendBufCons {
   302  		return v.SendBufProd - v.SendBufCons
   303  	} else {
   304  		return v.SendBufProd + SendBufSize - v.SendBufCons
   305  	}
   306  }
   307  
   308  // call it with unlocked mutex!
   309  func (c *OneConnection) SendingPaused() (res bool) {
   310  	c.Mutex.Lock()
   311  	res = c.BytesToSent() > SendBufSize/2
   312  	c.Mutex.Unlock()
   313  	return
   314  }
   315  
   316  func (v *OneConnection) GetStats(res *ConnInfo) {
   317  	v.Mutex.Lock()
   318  	res.ID = v.ConnID
   319  	res.PeerIp = v.PeerAddr.Ip()
   320  	if v.Conn != nil {
   321  		res.LocalAddr = v.Conn.LocalAddr().String()
   322  		res.RemoteAddr = v.Conn.RemoteAddr().String()
   323  	}
   324  	res.NetworkNodeStruct = v.Node
   325  	res.ConnectionStatus = v.X
   326  	res.BytesToSend = v.BytesToSent()
   327  	res.BlocksInProgress = len(v.GetBlockInProgress)
   328  	res.InvsToSend = len(v.PendingInvs)
   329  	res.AveragePing = v.GetAveragePing()
   330  
   331  	res.Counters = make(map[string]uint64, len(v.counters))
   332  	for k, v := range v.counters {
   333  		res.Counters[k] = v
   334  	}
   335  
   336  	res.InvsDone = len(v.InvDone.History)
   337  	res.BlocksReceived = len(v.blocksreceived)
   338  	res.GetMPInProgress = len(v.GetMP) != 0
   339  
   340  	v.Mutex.Unlock()
   341  }
   342  
   343  func (c *OneConnection) SendRawMsg(cmd string, pl []byte) (e error) {
   344  	c.Mutex.Lock()
   345  
   346  	/*if c.X.Debug {
   347  		fmt.Println(c.ConnID, "sent", cmd, len(pl))
   348  	}*/
   349  
   350  	if !c.broken {
   351  		// we never allow the buffer to be totally full because then producer would be equal consumer
   352  		if bytes_left := SendBufSize - c.BytesToSent(); bytes_left <= len(pl)+24 {
   353  			c.Mutex.Unlock()
   354  			println(c.PeerAddr.Ip(), c.Node.Version, c.Node.Agent, "Peer Send Buffer Overflow @",
   355  				cmd, bytes_left, len(pl)+24, c.SendBufProd, c.SendBufCons, c.BytesToSent())
   356  			c.DoS("SendBufferOverflow")
   357  			common.CountSafe("PeerSendOverflow")
   358  			return errors.New("send buffer overflow")
   359  		}
   360  
   361  		if !common.NoCounters.Get() {
   362  			ssent := "sent_" + cmd
   363  			ssbts := "sbts_" + cmd
   364  			c.cntInc(ssent)
   365  			c.cntAdd(ssbts, uint64(len(pl)))
   366  			common.CountSafe(ssent)
   367  			common.CountSafeAdd(ssbts, uint64(len(pl)))
   368  		}
   369  		var sbuf [24]byte
   370  
   371  		c.X.LastCmdSent = cmd
   372  		c.X.LastBtsSent = uint32(len(pl))
   373  
   374  		binary.LittleEndian.PutUint32(sbuf[0:4], common.Version)
   375  		copy(sbuf[0:4], common.Magic[:])
   376  		copy(sbuf[4:16], cmd)
   377  		binary.LittleEndian.PutUint32(sbuf[16:20], uint32(len(pl)))
   378  
   379  		sh := btc.Sha2Sum(pl[:])
   380  		copy(sbuf[20:24], sh[:4])
   381  
   382  		c.append_to_send_buffer(sbuf[:])
   383  		c.append_to_send_buffer(pl)
   384  
   385  		if x := c.BytesToSent(); x > c.X.MaxSentBufSize {
   386  			c.X.MaxSentBufSize = x
   387  		}
   388  	}
   389  	c.Mutex.Unlock()
   390  	select {
   391  	case c.writing_thread_push <- true:
   392  	default:
   393  	}
   394  	return
   395  }
   396  
   397  // append_to_send_buffer assumes that there is enough room inside sendBuf.
   398  func (c *OneConnection) append_to_send_buffer(d []byte) {
   399  	room_left := SendBufSize - c.SendBufProd
   400  	if room_left >= len(d) {
   401  		copy(c.sendBuf[c.SendBufProd:], d)
   402  	} else {
   403  		copy(c.sendBuf[c.SendBufProd:], d[:room_left])
   404  		copy(c.sendBuf[:], d[room_left:])
   405  	}
   406  	c.SendBufProd = (c.SendBufProd + len(d)) & SendBufMask
   407  }
   408  
   409  func (c *OneConnection) Disconnect(dead bool, why string) {
   410  	c.Mutex.Lock()
   411  	if c.X.Debug {
   412  		print("Disconnect " + c.PeerAddr.Ip() + " (" + c.Node.Agent + ") because -" + why + "-\n> ")
   413  		//println("LastCmdSent:", c.X.LastCmdSent, c.X.LastBtsSent, "   LastCmdRcvd:", c.X.LastCmdRcvd, c.X.LastBtsRcvd)
   414  	}
   415  	c.dead = dead
   416  	c.broken = true
   417  	c.why_disconnected = why
   418  	c.Mutex.Unlock()
   419  }
   420  
   421  func (c *OneConnection) IsBroken() (res bool) {
   422  	c.Mutex.Lock()
   423  	res = c.broken
   424  	c.Mutex.Unlock()
   425  	return
   426  }
   427  
   428  func (c *OneConnection) DoS(why string) {
   429  	common.CountSafe("Ban" + why)
   430  	c.Mutex.Lock()
   431  	if c.X.Debug || c.X.Authorized {
   432  		print("BAN " + c.PeerAddr.Ip() + " (" + c.Node.Agent + ") because " + why + "\n> ")
   433  	}
   434  	c.banit = true
   435  	c.ban_reason = why
   436  	c.broken = true
   437  	c.Mutex.Unlock()
   438  }
   439  
   440  func (c *OneConnection) Misbehave(why string, how_much int) (res bool) {
   441  	c.Mutex.Lock()
   442  	if c.X.Debug || c.X.Authorized {
   443  		print("Misbehave " + c.PeerAddr.Ip() + " (" + c.Node.Agent + ") because " + why + "\n> ")
   444  	}
   445  	if !c.banit {
   446  		common.CountSafe("Bad" + why)
   447  		c.misbehave += how_much
   448  		if c.misbehave >= 1000 {
   449  			common.CountSafe("BanMisbehave")
   450  			res = true
   451  			c.banit = true
   452  			c.ban_reason = "Bad" + why
   453  			c.broken = true
   454  			//print("Ban " + c.PeerAddr.Ip() + " (" + c.Node.Agent + ") because " + why + "\n> ")
   455  		}
   456  	} else {
   457  		common.CountSafe("Misb" + why)
   458  	}
   459  	c.Mutex.Unlock()
   460  	return
   461  }
   462  
   463  func (c *OneConnection) HandleError(e error) error {
   464  	if nerr, ok := e.(net.Error); ok && nerr.Timeout() {
   465  		//fmt.Println("Just a timeout - ignore")
   466  		return nil
   467  	}
   468  	c.recv.hdr_len = 0
   469  	c.recv.dat = nil
   470  	c.Disconnect(true, "Error:"+e.Error())
   471  	return e
   472  }
   473  
   474  func (c *OneConnection) FetchMessage() (ret *BCmsg, timeout_or_data bool) {
   475  	var e error
   476  	var n int
   477  
   478  	for c.recv.hdr_len < 24 {
   479  		n, e = common.SockRead(c.Conn, c.recv.hdr[c.recv.hdr_len:24])
   480  		if n < 0 {
   481  			n = 0
   482  		} else {
   483  			timeout_or_data = true
   484  		}
   485  		c.Mutex.Lock()
   486  		if n > 0 {
   487  			c.X.BytesReceived += uint64(n)
   488  			c.X.LastDataGot = time.Now()
   489  			c.recv.hdr_len += n
   490  		}
   491  		if e != nil {
   492  			c.Mutex.Unlock()
   493  			c.HandleError(e)
   494  			return // Make sure to exit here, in case of timeout
   495  		}
   496  		if c.recv.hdr_len >= 4 && !bytes.Equal(c.recv.hdr[:4], common.Magic[:]) {
   497  			if c.X.Debug {
   498  				fmt.Printf("BadMagic from %s %s \n hdr:%s  n:%d\n R: %s %d / S: %s %d\n> ", c.PeerAddr.Ip(), c.Node.Agent,
   499  					hex.EncodeToString(c.recv.hdr[:c.recv.hdr_len]), n,
   500  					c.X.LastCmdRcvd, c.X.LastBtsRcvd, c.X.LastCmdSent, c.X.LastBtsSent)
   501  			}
   502  			c.Mutex.Unlock()
   503  			common.CountSafe("NetBadMagic")
   504  			c.Ban("NetBadMagic")
   505  			return
   506  		}
   507  		if c.broken {
   508  			c.Mutex.Unlock()
   509  			return
   510  		}
   511  		if c.recv.hdr_len == 24 {
   512  			c.recv.pl_len = binary.LittleEndian.Uint32(c.recv.hdr[16:20])
   513  			c.recv.cmd = strings.TrimRight(string(c.recv.hdr[4:16]), "\000")
   514  			c.Mutex.Unlock()
   515  		} else {
   516  			if c.recv.hdr_len > 24 {
   517  				// hard to belive but I saw this happening twice on Windows
   518  				println("ERROR: hdr_len > 24 after receiving", n, "bytes")
   519  				c.Mutex.Unlock()
   520  				common.CountSafe("SockReadOverflow")
   521  				c.Disconnect(true, "SockReadOverflow")
   522  				return
   523  			}
   524  			c.Mutex.Unlock()
   525  			return
   526  		}
   527  	}
   528  
   529  	if c.recv.pl_len > 0 {
   530  		if c.recv.dat == nil {
   531  			msi := maxmsgsize(c.recv.cmd)
   532  			if c.recv.pl_len > msi {
   533  				c.DoS("Big-" + c.recv.cmd)
   534  				return
   535  			}
   536  			c.Mutex.Lock()
   537  			c.recv.dat = make([]byte, c.recv.pl_len)
   538  			c.recv.datlen = 0
   539  			c.Mutex.Unlock()
   540  		}
   541  		if c.recv.datlen < c.recv.pl_len {
   542  			n, e = common.SockRead(c.Conn, c.recv.dat[c.recv.datlen:])
   543  			if n < 0 {
   544  				n = 0
   545  			} else {
   546  				timeout_or_data = true
   547  			}
   548  			if n > 0 {
   549  				c.Mutex.Lock()
   550  				c.X.BytesReceived += uint64(n)
   551  				c.recv.datlen += uint32(n)
   552  				c.Mutex.Unlock()
   553  				if c.recv.datlen > c.recv.pl_len {
   554  					println(c.PeerAddr.Ip(), "is sending more of", c.recv.cmd, "then it should have", c.recv.datlen, c.recv.pl_len)
   555  					c.DoS("MsgSizeMismatch")
   556  					return
   557  				}
   558  			}
   559  			if e != nil {
   560  				c.HandleError(e)
   561  				return
   562  			}
   563  			if c.MutexGetBool(&c.broken) || c.recv.datlen < c.recv.pl_len {
   564  				return
   565  			}
   566  		}
   567  	}
   568  
   569  	sh := btc.Sha2Sum(c.recv.dat)
   570  	if !bytes.Equal(c.recv.hdr[20:24], sh[:4]) {
   571  		//println(c.PeerAddr.Ip(), "Msg checksum error")
   572  		c.DoS("MsgBadChksum")
   573  		return
   574  	}
   575  
   576  	ret = new(BCmsg)
   577  	ret.cmd = c.recv.cmd
   578  	ret.pl = c.recv.dat
   579  
   580  	c.Mutex.Lock()
   581  	c.recv.hdr_len = 0
   582  	c.recv.cmd = ""
   583  	c.recv.dat = nil
   584  
   585  	c.X.LastCmdRcvd = ret.cmd
   586  	c.X.LastBtsRcvd = uint32(len(ret.pl))
   587  
   588  	if !common.NoCounters.Get() {
   589  		srcvd := "rcvd_" + ret.cmd
   590  		srbts := "rbts_" + ret.cmd
   591  		c.cntInc(srcvd)
   592  		c.cntAdd(srbts, uint64(len(ret.pl)))
   593  		c.Mutex.Unlock()
   594  		common.CountSafe(srcvd)
   595  		common.CountSafeAdd(srbts, uint64(len(ret.pl)))
   596  	} else {
   597  		c.Mutex.Unlock()
   598  	}
   599  
   600  	c.LastMsgTime = time.Now()
   601  
   602  	/*if c.X.Debug {
   603  		fmt.Println(c.ConnID, "rcvd", cmd.cmd, len(cmd.pl))
   604  	}*/
   605  
   606  	return
   607  }
   608  
   609  // Check c.X.AuthAckGot before calling this function
   610  func (c *OneConnection) GetMPNow() {
   611  	if common.GetBool(&common.CFG.TXPool.Enabled) {
   612  		select {
   613  		case c.GetMP <- true:
   614  		default:
   615  			fmt.Println(c.ConnID, "GetMP channel full")
   616  		}
   617  	}
   618  }
   619  
   620  func (c *OneConnection) writing_thread() {
   621  	for !c.IsBroken() {
   622  		c.Mutex.Lock() // protect access to c.SendBufProd
   623  
   624  		if c.SendBufProd == c.SendBufCons {
   625  			c.Mutex.Unlock()
   626  			// wait for a new write, but time out just in case
   627  			select {
   628  			case <-c.writing_thread_push:
   629  			case <-time.After(10 * time.Millisecond):
   630  			}
   631  			continue
   632  		}
   633  
   634  		bytes_to_send := c.SendBufProd - c.SendBufCons
   635  		c.Mutex.Unlock() // unprotect access to c.SendBufProd
   636  
   637  		if bytes_to_send < 0 {
   638  			bytes_to_send += SendBufSize
   639  		}
   640  		if c.SendBufCons+bytes_to_send > SendBufSize {
   641  			bytes_to_send = SendBufSize - c.SendBufCons
   642  		}
   643  
   644  		n, e := common.SockWrite(c.Conn, c.sendBuf[c.SendBufCons:c.SendBufCons+bytes_to_send])
   645  		if n > 0 {
   646  			c.Mutex.Lock()
   647  			c.X.LastSent = time.Now()
   648  			c.X.BytesSent += uint64(n)
   649  			c.SendBufCons = (c.SendBufCons + n) & SendBufMask
   650  			c.Mutex.Unlock()
   651  		} else if e != nil {
   652  			c.Disconnect(true, "SendErr:"+e.Error())
   653  		} else if n < 0 {
   654  			// It comes here if we could not send a single byte because of BW limit
   655  			time.Sleep(10 * time.Millisecond)
   656  		}
   657  	}
   658  	c.writing_thread_done.Done()
   659  }
   660  
   661  func ConnectionActive(ad *peersdb.PeerAddr) (yes bool) {
   662  	Mutex_net.Lock()
   663  	_, yes = OpenCons[ad.UniqID()]
   664  	Mutex_net.Unlock()
   665  	return
   666  }
   667  
   668  // maxmsgsize returns maximum accepted payload size of a given type of message.
   669  // For wider compatibility, we assume that any var_len may be up to 9 bytes.
   670  func maxmsgsize(cmd string) uint32 {
   671  	switch cmd {
   672  	case "inv":
   673  		return 9 + 50000*36 // the spec says "max 50000 entries"
   674  	case "tx":
   675  		return 500e3 // max segwit tx size 500KB
   676  	case "addr":
   677  		return 9 + 1000*30 // max 1000 addrs
   678  	case "block":
   679  		return 4e6 // max segwit block size 4MB
   680  	case "getblocks":
   681  		return 4 + 9 + 101*32 + 32 // MAX_LOCATOR_SZ = 101
   682  	case "getdata":
   683  		return 9 + 50000*36 // core: MAX_INV_SZ = 50000
   684  	case "headers":
   685  		return 9 + 2000*89 // core: MAX_HEADERS_RESULTS = 2000
   686  	case "getheaders":
   687  		return 4 + 9 + 101*32 + 32 // MAX_LOCATOR_SZ = 101
   688  	case "cmpctblock":
   689  		return 1e6 // 1MB shall be enough
   690  	case "getblocktxn":
   691  		return 1e6 // 1MB shall be enough
   692  	case "blocktxn":
   693  		return 4e6 // all txs that can fit withing max size block
   694  	case "notfound":
   695  		return 9 + 50000*36 // same as maximum size of getdata
   696  	case "getmp":
   697  		return 9 + 8*MAX_GETMP_TXS
   698  	default:
   699  		return 1024 // Any other type of block: maximum 1KB payload limit
   700  	}
   701  }
   702  
   703  func NetCloseAll() {
   704  	sta := time.Now()
   705  	println("Closing network")
   706  	common.NetworkClosed.Set()
   707  	common.SetBool(&common.ListenTCP, false)
   708  	Mutex_net.Lock()
   709  	if InConsActive > 0 || OutConsActive > 0 {
   710  		for _, v := range OpenCons {
   711  			v.Disconnect(false, "CloseAll")
   712  		}
   713  	}
   714  	Mutex_net.Unlock()
   715  	time.Sleep(1e9) // give one second for WebUI requests to complete
   716  	// now wait for all the connections to close
   717  	for {
   718  		Mutex_net.Lock()
   719  		all_done := len(OpenCons) == 0
   720  		Mutex_net.Unlock()
   721  		if all_done {
   722  			return
   723  		}
   724  		if time.Since(sta) > 5*time.Second {
   725  			Mutex_net.Lock()
   726  			fmt.Println("Still have open connections:", InConsActive, OutConsActive, len(OpenCons), "- please report")
   727  			Mutex_net.Unlock()
   728  			break
   729  		}
   730  		time.Sleep(1e7)
   731  	}
   732  	for TCPServerStarted {
   733  		time.Sleep(1e7) // give one second for all the pending messages to get processed
   734  	}
   735  }
   736  
   737  func DropPeer(conid uint32) {
   738  	Mutex_net.Lock()
   739  	defer Mutex_net.Unlock()
   740  	for _, v := range OpenCons {
   741  		if uint32(conid) == v.ConnID {
   742  			if v.X.IsSpecial {
   743  				v.Disconnect(false, "FromUI")
   744  			} else {
   745  				v.DoS("FromUI")
   746  			}
   747  			return
   748  		}
   749  	}
   750  	fmt.Println("DropPeer: There is no such an active connection", conid)
   751  }
   752  
   753  // GetMP() is called from UI, to force asking the given peer for its mempool
   754  func GetMP(conid uint32) {
   755  	Mutex_net.Lock()
   756  	for _, v := range OpenCons {
   757  		if uint32(conid) == v.ConnID {
   758  			Mutex_net.Unlock()
   759  			v.Mutex.Lock()
   760  			yes := v.X.AuthAckGot // don't bother if we are not authorized there
   761  			v.Mutex.Unlock()
   762  			if yes {
   763  				v.GetMPNow()
   764  			}
   765  			return
   766  		}
   767  	}
   768  	Mutex_net.Unlock()
   769  	fmt.Println("GetMP: There is no such an active connection", conid)
   770  }
   771  
   772  func GetMoreHeaders() {
   773  	Mutex_net.Lock()
   774  	for _, v := range OpenCons {
   775  		v.ReceiveHeadersNow()
   776  	}
   777  	Mutex_net.Unlock()
   778  }
   779  
   780  func BlocksToGetCnt() (res int) {
   781  	MutexRcv.Lock()
   782  	res = len(BlocksToGet)
   783  	MutexRcv.Unlock()
   784  	return
   785  }
   786  
   787  func init() {
   788  	rand.Read(nonce[:])
   789  }