Exemplo n.º 1
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
}
Exemplo n.º 2
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.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()
}