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() }
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 }
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 }
// 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() }
// 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() }