Пример #1
0
func ExpirePeers() {
	peerdb_mutex.Lock()
	var delcnt uint32
	now := time.Now()
	todel := make([]qdb.KeyType, PeerDB.Count())
	PeerDB.Browse(func(k qdb.KeyType, v []byte) uint32 {
		ptim := binary.LittleEndian.Uint32(v[0:4])
		if now.After(time.Unix(int64(ptim), 0).Add(ExpirePeerAfter)) {
			todel[delcnt] = k // we cannot call Del() from here
			delcnt++
		}
		return 0
	})
	if delcnt > 0 {
		common.CountSafeAdd("PeersExpired", uint64(delcnt))
		for delcnt > 0 {
			delcnt--
			PeerDB.Del(todel[delcnt])
		}
		common.CountSafe("PeerDefragsDone")
		PeerDB.Defrag()
	} else {
		common.CountSafe("PeerDefragsNone")
	}
	peerdb_mutex.Unlock()
}
Пример #2
0
func (c *OneConnection) SendRawMsg(cmd string, pl []byte) (e error) {
	c.Mutex.Lock()

	if c.Send.Buf != nil {
		// Before adding more data to the buffer, check the limit
		if len(c.Send.Buf) > MaxSendBufferSize {
			c.Mutex.Unlock()
			if common.DebugLevel > 0 {
				println(c.PeerAddr.Ip(), "Peer Send Buffer Overflow")
			}
			c.Disconnect()
			common.CountSafe("PeerSendOverflow")
			return errors.New("Send buffer overflow")
		}
	} else {
		c.Send.LastSent = time.Now()
	}

	common.CountSafe("sent_" + cmd)
	common.CountSafeAdd("sbts_"+cmd, uint64(len(pl)))
	sbuf := make([]byte, 24+len(pl))

	c.LastCmdSent = cmd
	c.LastBtsSent = uint32(len(pl))

	binary.LittleEndian.PutUint32(sbuf[0:4], common.Version)
	copy(sbuf[0:4], common.Magic[:])
	copy(sbuf[4:16], cmd)
	binary.LittleEndian.PutUint32(sbuf[16:20], uint32(len(pl)))

	sh := btc.Sha2Sum(pl[:])
	copy(sbuf[20:24], sh[:4])
	copy(sbuf[24:], pl)

	c.Send.Buf = append(c.Send.Buf, sbuf...)

	if common.DebugLevel < 0 {
		fmt.Println(cmd, len(c.Send.Buf), "->", c.PeerAddr.Ip())
	}
	c.Mutex.Unlock()
	//println(len(c.Send.Buf), "queued for seding to", c.PeerAddr.Ip())
	return
}
Пример #3
0
func (c *OneConnection) SendRawMsg(cmd string, pl []byte) (e error) {
	c.Mutex.Lock()
	if !c.broken {
		// we never allow the buffer to be totally full because then producer would be equal consumer
		if bytes_left := SendBufSize - c.BytesToSent(); bytes_left <= len(pl)+24 {
			c.Mutex.Unlock()
			/*println(c.PeerAddr.Ip(), c.Node.Version, c.Node.Agent, "Peer Send Buffer Overflow @",
			cmd, bytes_left, len(pl)+24, c.SendBufProd, c.SendBufCons, c.BytesToSent())*/
			c.Disconnect()
			common.CountSafe("PeerSendOverflow")
			return errors.New("Send buffer overflow")
		}

		c.counters["sent_"+cmd]++
		c.counters["sbts_"+cmd] += uint64(len(pl))

		common.CountSafe("sent_" + cmd)
		common.CountSafeAdd("sbts_"+cmd, uint64(len(pl)))
		var sbuf [24]byte

		c.X.LastCmdSent = cmd
		c.X.LastBtsSent = uint32(len(pl))

		binary.LittleEndian.PutUint32(sbuf[0:4], common.Version)
		copy(sbuf[0:4], common.Magic[:])
		copy(sbuf[4:16], cmd)
		binary.LittleEndian.PutUint32(sbuf[16:20], uint32(len(pl)))

		sh := btc.Sha2Sum(pl[:])
		copy(sbuf[20:24], sh[:4])

		c.append_to_send_buffer(sbuf[:])
		c.append_to_send_buffer(pl)

		if x := c.BytesToSent(); x > c.X.MaxSentBufSize {
			c.X.MaxSentBufSize = x
		}
	}
	c.Mutex.Unlock()
	return
}
Пример #4
0
// Process that handles communication with a single peer
func (c *OneConnection) Run() {
	c.SendVersion()

	c.Mutex.Lock()
	c.LastDataGot = time.Now()
	c.NextBlocksAsk = time.Now()                 // ask for blocks ASAP
	c.NextGetAddr = time.Now()                   // do getaddr ~10 seconds from now
	c.NextPing = time.Now().Add(5 * time.Second) // do first ping ~5 seconds from now
	c.Mutex.Unlock()

	for !c.IsBroken() {
		c.Mutex.Lock()
		c.LoopCnt++
		c.Mutex.Unlock()

		cmd := c.FetchMessage()
		if c.IsBroken() {
			break
		}

		// Timeout ping in progress
		if c.PingInProgress != nil && time.Now().After(c.LastPingSent.Add(PingTimeout)) {
			if common.DebugLevel > 0 {
				println(c.PeerAddr.Ip(), "ping timeout")
			}
			common.CountSafe("PingTimeout")
			c.HandlePong() // this will set LastPingSent to nil
		}

		if cmd == nil {
			c.Tick()
			continue
		}

		c.Mutex.Lock()
		c.LastDataGot = time.Now()
		c.LastCmdRcvd = cmd.cmd
		c.LastBtsRcvd = uint32(len(cmd.pl))
		c.Mutex.Unlock()

		c.PeerAddr.Alive()
		if common.DebugLevel < 0 {
			fmt.Println(c.PeerAddr.Ip(), "->", cmd.cmd, len(cmd.pl))
		}

		if c.Send.Buf != nil && len(c.Send.Buf) > SendBufSizeHoldOn {
			common.CountSafe("hold_" + cmd.cmd)
			common.CountSafeAdd("hbts_"+cmd.cmd, uint64(len(cmd.pl)))
			continue
		}

		common.CountSafe("rcvd_" + cmd.cmd)
		common.CountSafeAdd("rbts_"+cmd.cmd, uint64(len(cmd.pl)))

		switch cmd.cmd {
		case "version":
			er := c.HandleVersion(cmd.pl)
			if er != nil {
				println("version:", er.Error())
				c.Disconnect()
			}

		case "verack":
			c.VerackReceived = true
			if common.CFG.Net.ListenTCP {
				c.SendOwnAddr()
			}

		case "inv":
			c.ProcessInv(cmd.pl)

		case "tx":
			if common.CFG.TXPool.Enabled {
				c.ParseTxNet(cmd.pl)
			}

		case "addr":
			ParseAddr(cmd.pl)

		case "block": //block received
			netBlockReceived(c, cmd.pl)

		case "getblocks":
			c.GetBlocks(cmd.pl)

		case "getdata":
			c.ProcessGetData(cmd.pl)

		case "getaddr":
			c.SendAddr()

		case "alert":
			c.HandleAlert(cmd.pl)

		case "ping":
			re := make([]byte, len(cmd.pl))
			copy(re, cmd.pl)
			c.SendRawMsg("pong", re)

		case "pong":
			if c.PingInProgress == nil {
				common.CountSafe("PongUnexpected")
			} else if bytes.Equal(cmd.pl, c.PingInProgress) {
				c.HandlePong()
			} else {
				common.CountSafe("PongMismatch")
			}

		case "getheaders":
			c.GetHeaders(cmd.pl)

		case "notfound":
			common.CountSafe("NotFound")

		default:
			if common.DebugLevel > 0 {
				println(cmd.cmd, "from", c.PeerAddr.Ip())
			}
		}
	}
	c.Mutex.Lock()
	ban := c.banit
	c.Mutex.Unlock()
	if ban {
		c.PeerAddr.Ban()
		common.CountSafe("PeersBanned")
	} else if c.Incoming {
		HammeringMutex.Lock()
		RecentlyDisconencted[c.PeerAddr.NetAddr.Ip4] = time.Now()
		HammeringMutex.Unlock()
	}
	if common.DebugLevel > 0 {
		println("Disconnected from", c.PeerAddr.Ip())
	}
	c.NetConn.Close()
}
Пример #5
0
// Process that handles communication with a single peer
func (c *OneConnection) Run() {
	c.SendVersion()

	c.Mutex.Lock()
	now := time.Now()
	c.X.LastDataGot = now
	c.nextMaintanence = now.Add(time.Minute)
	c.LastPingSent = now.Add(5*time.Second - common.PingPeerEvery) // do first ping ~5 seconds from now
	c.Mutex.Unlock()

	for !c.IsBroken() {
		if c.IsBroken() {
			break
		}

		if c.SendPendingData() {
			continue // Do now read the socket if we have pending data to send
		}

		cmd := c.FetchMessage()

		if cmd == nil {
			c.Tick()
			continue
		}

		if c.X.VerackReceived {
			c.PeerAddr.Alive()
		}
		c.Mutex.Lock()
		c.counters["rcvd_"+cmd.cmd]++
		c.counters["rbts_"+cmd.cmd] += uint64(len(cmd.pl))
		c.X.LastDataGot = time.Now()
		c.X.LastCmdRcvd = cmd.cmd
		c.X.LastBtsRcvd = uint32(len(cmd.pl))
		c.Mutex.Unlock()

		if common.DebugLevel < 0 {
			fmt.Println(c.PeerAddr.Ip(), "->", cmd.cmd, len(cmd.pl))
		}

		common.CountSafe("rcvd_" + cmd.cmd)
		common.CountSafeAdd("rbts_"+cmd.cmd, uint64(len(cmd.pl)))

		switch cmd.cmd {
		case "version":
			er := c.HandleVersion(cmd.pl)
			if er != nil {
				println("version msg error:", er.Error())
				c.Disconnect()
				break
			}
			if c.Node.DoNotRelayTxs {
				c.DoS("SPV")
				break
			}
			if c.Node.Version >= 70012 {
				c.SendRawMsg("sendheaders", nil)
				if c.Node.Version >= 70013 {
					if common.CFG.TXPool.FeePerByte != 0 {
						var pl [8]byte
						binary.LittleEndian.PutUint64(pl[:], 1000*common.CFG.TXPool.FeePerByte)
						c.SendRawMsg("feefilter", pl[:])
					}
					if c.Node.Version >= 70014 {
						if (c.Node.Services & SERVICE_SEGWIT) == 0 {
							// if the node does not support segwit, request compact blocks
							// only if we have not achieved he segwit enforcement moment
							if common.BlockChain.Consensus.Enforce_SEGWIT == 0 ||
								common.Last.BlockHeight() < common.BlockChain.Consensus.Enforce_SEGWIT {
								c.SendRawMsg("sendcmpct", []byte{0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
							}
						} else {
							c.SendRawMsg("sendcmpct", []byte{0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
						}
					}
				}
			}

		case "verack":
			c.X.VerackReceived = true
			c.PeerAddr.Services = c.Node.Services
			c.PeerAddr.Save()
			if common.IsListenTCP() {
				c.SendOwnAddr()
			}

		case "inv":
			c.ProcessInv(cmd.pl)

		case "tx":
			if common.CFG.TXPool.Enabled {
				c.ParseTxNet(cmd.pl)
			}

		case "addr":
			c.ParseAddr(cmd.pl)

		case "block": //block received
			netBlockReceived(c, cmd.pl)

		case "getblocks":
			c.GetBlocks(cmd.pl)

		case "getdata":
			c.ProcessGetData(cmd.pl)

		case "getaddr":
			if !c.X.GetAddrDone {
				c.SendAddr()
				c.X.GetAddrDone = true
			} else {
				c.Mutex.Lock()
				c.counters["SecondGetAddr"]++
				c.Mutex.Unlock()
				if c.Misbehave("SecondGetAddr", 1000/20) {
					break
				}
			}

		case "ping":
			re := make([]byte, len(cmd.pl))
			copy(re, cmd.pl)
			c.SendRawMsg("pong", re)

		case "pong":
			if c.PingInProgress == nil {
				common.CountSafe("PongUnexpected")
			} else if bytes.Equal(cmd.pl, c.PingInProgress) {
				c.HandlePong()
			} else {
				common.CountSafe("PongMismatch")
			}

		case "getheaders":
			c.GetHeaders(cmd.pl)

		case "notfound":
			common.CountSafe("NotFound")

		case "headers":
			if c.HandleHeaders(cmd.pl) > 0 {
				c.sendGetHeaders()
			}

		case "sendheaders":
			c.Node.SendHeaders = true

		case "feefilter":
			if len(cmd.pl) >= 8 {
				c.X.MinFeeSPKB = int64(binary.LittleEndian.Uint64(cmd.pl[:8]))
				//println(c.PeerAddr.Ip(), c.Node.Agent, "feefilter", c.X.MinFeeSPKB)
			}

		case "sendcmpct":
			if len(cmd.pl) >= 9 {
				version := binary.LittleEndian.Uint64(cmd.pl[1:9])
				if version > c.Node.SendCmpctVer {
					//println(c.ConnID, "sendcmpct", cmd.pl[0])
					c.Node.SendCmpctVer = version
					c.Node.HighBandwidth = cmd.pl[0] == 1
				} else {
					c.Mutex.Lock()
					c.counters[fmt.Sprint("SendCmpctV", version)]++
					c.Mutex.Unlock()
				}
			} else {
				println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "sendcmpct", hex.EncodeToString(cmd.pl))
			}

		case "cmpctblock":
			c.ProcessCmpctBlock(cmd.pl)

		case "getblocktxn":
			c.ProcessGetBlockTxn(cmd.pl)
			//println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "getblocktxn", hex.EncodeToString(cmd.pl))

		case "blocktxn":
			c.ProcessBlockTxn(cmd.pl)
			//println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "blocktxn", hex.EncodeToString(cmd.pl))

		default:
			if common.DebugLevel > 0 {
				println(cmd.cmd, "from", c.PeerAddr.Ip())
			}
		}
	}

	c.Mutex.Lock()
	MutexRcv.Lock()
	for k, _ := range c.GetBlockInProgress {
		if rec, ok := BlocksToGet[k]; ok {
			rec.InProgress--
		} else {
			//println("ERROR! Block", bip.hash.String(), "in progress, but not in BlocksToGet")
		}
	}
	MutexRcv.Unlock()

	ban := c.banit
	c.Mutex.Unlock()
	if ban {
		c.PeerAddr.Ban()
		common.CountSafe("PeersBanned")
	} else if c.X.Incomming {
		HammeringMutex.Lock()
		RecentlyDisconencted[c.PeerAddr.NetAddr.Ip4] = time.Now()
		HammeringMutex.Unlock()
	}
	if common.DebugLevel != 0 {
		println("Disconnected from", c.PeerAddr.Ip())
	}
	c.Conn.Close()
}