You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

174 lines
5.6 KiB

package p2p
import (
"context"
"errors"
"fmt"
"net"
"net/url"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/p2p/conn"
)
const (
defaultProtocol Protocol = MConnProtocol
)
// Transport is an arbitrary mechanism for exchanging bytes with a peer.
type Transport interface {
// Accept waits for the next inbound connection on a listening endpoint. If
// this returns io.EOF or ErrTransportClosed the transport should be
// considered closed and further Accept() calls are futile.
Accept(context.Context) (Connection, error)
// Dial creates an outbound connection to an endpoint.
Dial(context.Context, Endpoint) (Connection, error)
// Endpoints lists endpoints the transport is listening on. Any endpoint IP
// addresses do not need to be normalized in any way (e.g. 0.0.0.0 is
// valid), as they should be preprocessed before being advertised.
Endpoints() []Endpoint
// Close stops accepting new connections, but does not close active connections.
Close() error
// SetChannelDescriptors sets the channel descriptors for the transport.
// FIXME: This is only here for compatibility with the current Switch code.
SetChannelDescriptors(chDescs []*conn.ChannelDescriptor)
}
// Protocol identifies a transport protocol.
type Protocol string
// Endpoint represents a transport connection endpoint, either local or remote.
type Endpoint struct {
// PeerID specifies the peer ID of the endpoint.
//
// FIXME: This is here for backwards-compatibility with the existing MConn
// protocol, we should consider moving this higher in the stack (i.e. to
// the router).
PeerID NodeID
// Protocol specifies the transport protocol, used by the router to pick a
// transport for an endpoint.
Protocol Protocol
// Path is an optional, arbitrary transport-specific path or identifier.
Path string
// IP is an IP address (v4 or v6) to connect to. If set, this defines the
// endpoint as a networked endpoint.
IP net.IP
// Port is a network port (either TCP or UDP). If not set, a default port
// may be used depending on the protocol.
Port uint16
}
// PeerAddress converts the endpoint into a peer address URL.
func (e Endpoint) PeerAddress() PeerAddress {
u := &url.URL{
Scheme: string(e.Protocol),
User: url.User(string(e.PeerID)),
}
if e.IP != nil {
u.Host = e.IP.String()
if e.Port > 0 {
u.Host = net.JoinHostPort(u.Host, fmt.Sprintf("%v", e.Port))
}
u.Path = e.Path
} else {
u.Opaque = e.Path
}
return PeerAddress{URL: u}
}
// String formats an endpoint as a URL string.
func (e Endpoint) String() string {
return e.PeerAddress().URL.String()
}
// Validate validates an endpoint.
func (e Endpoint) Validate() error {
switch {
case e.PeerID == "":
return errors.New("endpoint has no peer ID")
case e.Protocol == "":
return errors.New("endpoint has no protocol")
case len(e.IP) == 0 && len(e.Path) == 0:
return errors.New("endpoint must have either IP or path")
case e.Port > 0 && len(e.IP) == 0:
return fmt.Errorf("endpoint has port %v but no IP", e.Port)
default:
return nil
}
}
// NetAddress returns a NetAddress for the endpoint.
// FIXME: This is temporary for compatibility with the old P2P stack.
func (e Endpoint) NetAddress() *NetAddress {
return &NetAddress{
ID: e.PeerID,
IP: e.IP,
Port: e.Port,
}
}
// Connection represents an established connection between two endpoints.
//
// FIXME: This is a temporary interface while we figure out whether we'll be
// adopting QUIC or not. If we do, this should be a byte-oriented multi-stream
// interface with one goroutine consuming each stream, and the MConnection
// transport either needs protocol changes or a shim. For details, see:
// https://github.com/tendermint/spec/pull/227
//
// FIXME: The interface is currently very broad in order to accommodate
// MConnection behavior that the rest of the P2P stack relies on. This should be
// removed once the P2P core is rewritten.
type Connection interface {
// ReceiveMessage returns the next message received on the connection,
// blocking until one is available. io.EOF is returned when closed.
ReceiveMessage() (chID byte, msg []byte, err error)
// SendMessage sends a message on the connection.
// FIXME: For compatibility with the current Peer, it returns an additional
// boolean false if the message timed out waiting to be accepted into the
// send buffer.
SendMessage(chID byte, msg []byte) (bool, error)
// TrySendMessage is a non-blocking version of SendMessage that returns
// immediately if the message buffer is full. It returns true if the message
// was accepted.
//
// FIXME: This is here for backwards-compatibility with the current Peer
// code, and should be removed when possible.
TrySendMessage(chID byte, msg []byte) (bool, error)
// LocalEndpoint returns the local endpoint for the connection.
LocalEndpoint() Endpoint
// RemoteEndpoint returns the remote endpoint for the connection.
RemoteEndpoint() Endpoint
// PubKey returns the remote peer's public key.
PubKey() crypto.PubKey
// NodeInfo returns the remote peer's node info.
NodeInfo() NodeInfo
// Close closes the connection.
Close() error
// FlushClose flushes all pending sends and then closes the connection.
//
// FIXME: This only exists for backwards-compatibility with the current
// MConnection implementation. There should really be a separate Flush()
// method, but there is no easy way to synchronously flush pending data with
// the current MConnection structure.
FlushClose() error
// Status returns the current connection status.
// FIXME: Only here for compatibility with the current Peer code.
Status() conn.ConnectionStatus
}