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