neoneo-go/pkg/network/capability/capability.go
Roman Khimov 56b24bf83e capability: prevent panic on wrong capabilities receival
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0xad7b95]

goroutine 134 [running]:
github.com/nspcc-dev/neo-go/pkg/network/capability.(*Capability).DecodeBinary(0xc00024a300, 0xc00015c900)
        /home/rik/dev/neo-go/pkg/network/capability/capability.go:69 +0x85
github.com/nspcc-dev/neo-go/pkg/io.(*BinReader).ReadArray(0xc00015c900, 0xd54880, 0xc00018ecd8, 0xc00071fbe0, 0x1, 0x1)
        /home/rik/dev/neo-go/pkg/io/binaryReader.go:141 +0x22f
github.com/nspcc-dev/neo-go/pkg/network/capability.(*Capabilities).DecodeBinary(0xc00018ecd8, 0xc00015c900)
        /home/rik/dev/neo-go/pkg/network/capability/capability.go:17 +0x6d
github.com/nspcc-dev/neo-go/pkg/network/payload.(*AddressAndTime).DecodeBinary(0xc00018ecc0, 0xc00015c900)
        /home/rik/dev/neo-go/pkg/network/payload/address.go:34 +0x59
github.com/nspcc-dev/neo-go/pkg/io.(*BinReader).ReadArray(0xc00015c900, 0xcb9e00, 0xc00024a2a0, 0x0, 0x0, 0x0)
        /home/rik/dev/neo-go/pkg/io/binaryReader.go:141 +0x22f
github.com/nspcc-dev/neo-go/pkg/network/payload.(*AddressList).DecodeBinary(0xc00024a2a0, 0xc00015c900)
        /home/rik/dev/neo-go/pkg/network/payload/address.go:78 +0x54
github.com/nspcc-dev/neo-go/pkg/network.(*Message).decodePayload(0xc000277890, 0xc000292020, 0xc0003da000)
        /home/rik/dev/neo-go/pkg/network/message.go:158 +0x31a
github.com/nspcc-dev/neo-go/pkg/network.(*Message).Decode(0xc000277890, 0xc00071ff48, 0xc00036e090, 0xc000276e40)
        /home/rik/dev/neo-go/pkg/network/message.go:114 +0x19b
github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc00036e090)
        /home/rik/dev/neo-go/pkg/network/tcp_peer.go:154 +0x244
created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
        /home/rik/dev/neo-go/pkg/network/tcp_transport.go:40 +0x1ad
2020-05-29 00:11:54 +03:00

112 lines
2.5 KiB
Go

package capability
import (
"errors"
"github.com/nspcc-dev/neo-go/pkg/io"
)
// MaxCapabilities is the maximum number of capabilities per payload
const MaxCapabilities = 32
// Capabilities is a list of Capability
type Capabilities []Capability
// DecodeBinary implements Serializable interface.
func (cs *Capabilities) DecodeBinary(br *io.BinReader) {
br.ReadArray(cs, MaxCapabilities)
br.Err = cs.checkUniqueCapabilities()
}
// EncodeBinary implements Serializable interface.
func (cs *Capabilities) EncodeBinary(br *io.BinWriter) {
br.WriteArray(*cs)
}
// checkUniqueCapabilities checks whether payload capabilities have unique type.
func (cs Capabilities) checkUniqueCapabilities() error {
err := errors.New("capabilities with the same type are not allowed")
var isFullNode, isTCP, isWS bool
for _, cap := range cs {
switch cap.Type {
case FullNode:
if isFullNode {
return err
}
isFullNode = true
case TCPServer:
if isTCP {
return err
}
isTCP = true
case WSServer:
if isWS {
return err
}
isWS = true
}
}
return nil
}
// Capability describes network service available for node
type Capability struct {
Type Type
Data io.Serializable
}
// DecodeBinary implements Serializable interface.
func (c *Capability) DecodeBinary(br *io.BinReader) {
c.Type = Type(br.ReadB())
switch c.Type {
case FullNode:
c.Data = &Node{}
case TCPServer, WSServer:
c.Data = &Server{}
default:
br.Err = errors.New("unknown node capability type")
return
}
c.Data.DecodeBinary(br)
}
// EncodeBinary implements Serializable interface.
func (c *Capability) EncodeBinary(bw *io.BinWriter) {
if c.Data == nil {
bw.Err = errors.New("capability has no data")
return
}
bw.WriteB(byte(c.Type))
c.Data.EncodeBinary(bw)
}
// Node represents full node capability with start height
type Node struct {
StartHeight uint32
}
// DecodeBinary implements Serializable interface.
func (n *Node) DecodeBinary(br *io.BinReader) {
n.StartHeight = br.ReadU32LE()
}
// EncodeBinary implements Serializable interface.
func (n *Node) EncodeBinary(bw *io.BinWriter) {
bw.WriteU32LE(n.StartHeight)
}
// Server represents TCP or WS server capability with port
type Server struct {
// Port is the port this server is listening on
Port uint16
}
// DecodeBinary implements Serializable interface.
func (s *Server) DecodeBinary(br *io.BinReader) {
s.Port = br.ReadU16LE()
}
// EncodeBinary implements Serializable interface.
func (s *Server) EncodeBinary(bw *io.BinWriter) {
bw.WriteU16LE(s.Port)
}