Browse Source

p2p: explicit netaddress errors

pull/1519/head
Ethan Buchman 7 years ago
parent
commit
3ee1d7909e
3 changed files with 64 additions and 15 deletions
  1. +28
    -0
      p2p/errors.go
  2. +17
    -13
      p2p/netaddress.go
  3. +19
    -2
      p2p/node_info.go

+ 28
- 0
p2p/errors.go View File

@ -18,3 +18,31 @@ type ErrSwitchAuthenticationFailure struct {
func (e ErrSwitchAuthenticationFailure) Error() string { func (e ErrSwitchAuthenticationFailure) Error() string {
return fmt.Sprintf("Failed to authenticate peer. Dialed %v, but got peer with ID %s", e.Dialed, e.Got) return fmt.Sprintf("Failed to authenticate peer. Dialed %v, but got peer with ID %s", e.Dialed, e.Got)
} }
//-------------------------------------------------------------------
type ErrNetAddressNoID struct {
Addr string
}
func (e ErrNetAddressNoID) Error() string {
return fmt.Errorf("Address (%s) does not contain ID", e.Addr)
}
type ErrNetAddressInvalid struct {
Addr string
Err error
}
func (e ErrNetAddressInvalid) Error() string {
return fmt.Errorf("Invalid address (%s): %v", e.Addr, e.Err)
}
type ErrNetAddressLookup struct {
Addr string
Err error
}
func (e ErrNetAddressLookup) Error() string {
return fmt.Errorf("Error looking up host (%s): %v", e.Addr, e.Err)
}

+ 17
- 13
p2p/netaddress.go View File

@ -19,11 +19,13 @@ import (
// NetAddress defines information about a peer on the network // NetAddress defines information about a peer on the network
// including its ID, IP address, and port. // including its ID, IP address, and port.
type NetAddress struct { type NetAddress struct {
ID ID
IP net.IP
Port uint16
Name string // optional DNS name
str string
ID ID `json:"id"`
IP net.IP `json:"ip"`
Port uint16 `json:"port"`
Name string `json:"name"` // optional DNS name
// memoize .String()
str string
} }
// IDAddressString returns id@hostPort. // IDAddressString returns id@hostPort.
@ -57,10 +59,11 @@ func NewNetAddress(id ID, addr net.Addr) *NetAddress {
// NewNetAddressString returns a new NetAddress using the provided address in // NewNetAddressString returns a new NetAddress using the provided address in
// the form of "ID@IP:Port". // the form of "ID@IP:Port".
// Also resolves the host if host is not an IP. // Also resolves the host if host is not an IP.
// Errors are of type ErrNetAddressXxx where Xxx is in (NoID, Invalid, Lookup)
func NewNetAddressString(addr string) (*NetAddress, error) { func NewNetAddressString(addr string) (*NetAddress, error) {
spl := strings.Split(addr, "@") spl := strings.Split(addr, "@")
if len(spl) < 2 { if len(spl) < 2 {
return nil, fmt.Errorf("Address (%s) does not contain ID", addr)
return nil, ErrNetAddressNoID{addr}
} }
return NewNetAddressStringWithOptionalID(addr) return NewNetAddressStringWithOptionalID(addr)
} }
@ -77,11 +80,12 @@ func NewNetAddressStringWithOptionalID(addr string) (*NetAddress, error) {
idStr := spl[0] idStr := spl[0]
idBytes, err := hex.DecodeString(idStr) idBytes, err := hex.DecodeString(idStr)
if err != nil { if err != nil {
return nil, cmn.ErrorWrap(err, fmt.Sprintf("Address (%s) contains invalid ID", addrWithoutProtocol))
return nil, ErrNetAddressInvalid{addrWithoutProtocol, err}
} }
if len(idBytes) != IDByteLength { if len(idBytes) != IDByteLength {
return nil, fmt.Errorf("Address (%s) contains ID of invalid length (%d). Should be %d hex-encoded bytes",
addrWithoutProtocol, len(idBytes), IDByteLength)
return nil, ErrNetAddressInvalid{
addrWithoutProtocol,
fmt.Errorf("invalid hex length - got %d, expected %d", len(idBytes), IDByteLength)}
} }
id, addrWithoutProtocol = ID(idStr), spl[1] id, addrWithoutProtocol = ID(idStr), spl[1]
@ -89,7 +93,7 @@ func NewNetAddressStringWithOptionalID(addr string) (*NetAddress, error) {
host, portStr, err := net.SplitHostPort(addrWithoutProtocol) host, portStr, err := net.SplitHostPort(addrWithoutProtocol)
if err != nil { if err != nil {
return nil, err
return nil, ErrNetAddressInvalid{addrWithoutProtocol, err}
} }
ip := net.ParseIP(host) ip := net.ParseIP(host)
@ -97,7 +101,7 @@ func NewNetAddressStringWithOptionalID(addr string) (*NetAddress, error) {
if len(host) > 0 { if len(host) > 0 {
ips, err := net.LookupIP(host) ips, err := net.LookupIP(host)
if err != nil { if err != nil {
return nil, err
return nil, ErrNetAddressLookup{host, err}
} }
ip = ips[0] ip = ips[0]
} }
@ -105,7 +109,7 @@ func NewNetAddressStringWithOptionalID(addr string) (*NetAddress, error) {
port, err := strconv.ParseUint(portStr, 10, 16) port, err := strconv.ParseUint(portStr, 10, 16)
if err != nil { if err != nil {
return nil, err
return nil, ErrNetAddressInvalid{portStr, err}
} }
na := NewNetAddressIPPort(ip, uint16(port)) na := NewNetAddressIPPort(ip, uint16(port))
@ -121,7 +125,7 @@ func NewNetAddressStrings(addrs []string) ([]*NetAddress, []error) {
for _, addr := range addrs { for _, addr := range addrs {
netAddr, err := NewNetAddressString(addr) netAddr, err := NewNetAddressString(addr)
if err != nil { if err != nil {
errs = append(errs, fmt.Errorf("Error in address %s: %v", addr, err))
errs = append(errs, err)
} else { } else {
netAddrs = append(netAddrs, netAddr) netAddrs = append(netAddrs, netAddr)
} }


+ 19
- 2
p2p/node_info.go View File

@ -21,6 +21,7 @@ func MaxNodeInfoSize() int {
// between two peers during the Tendermint P2P handshake. // between two peers during the Tendermint P2P handshake.
type NodeInfo struct { type NodeInfo struct {
// Authenticate // Authenticate
// TODO: replace with NetAddress
ID ID `json:"id"` // authenticated identifier ID ID `json:"id"` // authenticated identifier
ListenAddr string `json:"listen_addr"` // accepting incoming ListenAddr string `json:"listen_addr"` // accepting incoming
@ -37,7 +38,9 @@ type NodeInfo struct {
// Validate checks the self-reported NodeInfo is safe. // Validate checks the self-reported NodeInfo is safe.
// It returns an error if there // It returns an error if there
// are too many Channels or any duplicate Channels.
// are too many Channels, if there are any duplicate Channels,
// if the ListenAddr is malformed, or if the ListenAddr is a host name
// that can not be resolved to some IP.
// TODO: constraints for Moniker/Other? Or is that for the UI ? // TODO: constraints for Moniker/Other? Or is that for the UI ?
func (info NodeInfo) Validate() error { func (info NodeInfo) Validate() error {
if len(info.Channels) > maxNumChannels { if len(info.Channels) > maxNumChannels {
@ -52,6 +55,13 @@ func (info NodeInfo) Validate() error {
} }
channels[ch] = struct{}{} channels[ch] = struct{}{}
} }
// ensure ListenAddr is good
netAddr, err := NewNetAddressString(IDAddressString(info.ID, info.ListenAddr))
if err != nil {
return err
}
return nil return nil
} }
@ -116,7 +126,14 @@ OUTER_LOOP:
func (info NodeInfo) NetAddress() *NetAddress { func (info NodeInfo) NetAddress() *NetAddress {
netAddr, err := NewNetAddressString(IDAddressString(info.ID, info.ListenAddr)) netAddr, err := NewNetAddressString(IDAddressString(info.ID, info.ListenAddr))
if err != nil { if err != nil {
panic(err) // everything should be well formed by now
switch err.(type) {
case ErrNetAddressLookup:
// XXX If the peer provided a host name and the lookup fails here
// we're out of luck.
// TODO: use a NetAddress in NodeInfo
default:
panic(err) // everything should be well formed by now
}
} }
return netAddr return netAddr
} }


Loading…
Cancel
Save