diff --git a/go.sum b/go.sum index 034ee22c..8348504a 100644 --- a/go.sum +++ b/go.sum @@ -89,6 +89,7 @@ github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/B github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-varint v0.0.1 h1:TR/0rdQtnNxuN2IhiB639xC3tWM4IUi7DkTBVTdGW/M= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= diff --git a/network/conn.go b/network/conn.go index e7844a0e..086d2e84 100644 --- a/network/conn.go +++ b/network/conn.go @@ -2,6 +2,7 @@ package network import ( "io" + "time" ic "github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/peer" @@ -27,8 +28,17 @@ type Conn interface { // Stat stores metadata pertaining to this conn. Stat() Stat + + // OnBetter is an callback when a better connection is found. + // OnBetter is threadsafe, it can be called even once the event raised and the + // callback we be yield. + OnBetter(OnBetterHandler) } +// OnBetterHandler are args to pass to Conn.OnBetter The time is the deadline +// before a hard close (fixed time not duration). +type OnBetterHandler func(time.Time) + // ConnSecurity is the interface that one can mix into a connection interface to // give it the security methods. type ConnSecurity interface { diff --git a/transport/transport.go b/transport/transport.go index 39a8fd38..a5dd1739 100644 --- a/transport/transport.go +++ b/transport/transport.go @@ -28,6 +28,9 @@ var AcceptTimeout = 60 * time.Second // capabilities required by libp2p: stream multiplexing, encryption and // peer authentication. // +// DEPREACATED try to use QCapableConn instead, using this will result in +// wrong transport choice when trying to pick a good one. +// // These capabilities may be natively provided by the transport, or they // may be shimmed via the "connection upgrade" process, which converts a // "raw" network connection into one that supports such capabilities by @@ -36,12 +39,65 @@ var AcceptTimeout = 60 * time.Second // CapableConn provides accessors for the local and remote multiaddrs used to // establish the connection and an accessor for the underlying Transport. type CapableConn interface { + BaseCapableConn + + // Transport returns the transport to which this connection belongs. + Transport() Transport +} + +// Quality is an estimation of how bad the connection will be. +// It must be short and fast to run. +// Lower is the returned score, better we expect the connection to be. +// Don't implement a pinging/monitoring algorithm quality must be deterministic. +// +// To see where to place your transport on the scale take a look at this (note: +// a proto with a Quality twice bigger is not twice slower or twice worst, it is +// just worst, like the place on a leaderboard): +// - TCP, 2^31, multiplexed stated continuous protocol (stream have fight for a +// place in the underlying protocol) +// - QUIC, 2^30, async stated discontinuous protocol (stream doesn't have to +// fight but there is time taken to open the connection and stream) +// - Circuit, router underlying connection quality + the number of hops * 8 +// (that consider that all router are equal but there is really no better than +// pinging/monitoring to know that) + 2^16 (base circuit value). +// +// Its also not needed to follow that closely, thing can be added if a proto add +// some overhead : +// - WS tcp score + 50 +// - WSS ws score + 150 +// +// If conn is on a private network Quality() must divide score by 2^8 (shift +// right by 8). +// If conn is on the loopback Quality() must divide score by 2^16 (shift right +// by 16). +// +// QCapableConn embed CapableConn but with `Quality() uint32` support. +type QCapableConn interface { + BaseCapableConn + + // Quality returns the Quality we can expect from the connection to this peer. + // That must be deterministic and fast. + Quality() uint32 + + // Transport returns the transport to which this connection belongs. + Transport() QTransport +} + +// CapableConnBase is used to build `CapableConn` and `QCapableConn` +type BaseCapableConn interface { mux.MuxedConn network.ConnSecurity network.ConnMultiaddrs +} - // Transport returns the transport to which this connection belongs. - Transport() Transport +// Score is used by transport to returns expectation about connection, might be +// different than what the connection actualy return but that DEPREACATED. +// (that will cause weird cancel issue) +type Score struct { + // Score of the future connection. + Quality uint32 + // Number of file descriptor expected to be open. + Fd uint8 } // Transport represents any device by which you can connect to and accept @@ -55,11 +111,36 @@ type CapableConn interface { // stream multiplexing and connection security (encryption and authentication). // // For a conceptual overview, see https://docs.libp2p.io/concepts/transport/ +// +// DEPREACATED try to use QTransport instead, using this will result in +// wrong transport choice when trying to pick a good one. type Transport interface { + BaseTransport + // Dial dials a remote peer. It should try to reuse local listener // addresses if possible but it may choose not to. Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (CapableConn, error) + // Listen listens on the passed multiaddr. + Listen(laddr ma.Multiaddr) (Listener, error) +} + +type QTransport interface { + BaseTransport + + // Dial dials a remote peer. It should try to reuse local listener + // addresses if possible but it may choose not to. + Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (QCapableConn, error) + + // Listen listens on the passed multiaddr. + Listen(laddr ma.Multiaddr) (QListener, error) + + // Score returns the Quality we can expect from the connection to this peer. + // That must be deterministic and fast. + Score(raddr ma.Multiaddr, p peer.ID) (Score, error) +} + +type BaseTransport interface { // CanDial returns true if this transport knows how to dial the given // multiaddr. // @@ -68,9 +149,6 @@ type Transport interface { // out addresses that we can't dial. CanDial(addr ma.Multiaddr) bool - // Listen listens on the passed multiaddr. - Listen(laddr ma.Multiaddr) (Listener, error) - // Protocol returns the set of protocols handled by this transport. // // See the Network interface for an explanation of how this is used. @@ -88,7 +166,20 @@ type Transport interface { // package, and also exposes a Multiaddr method as opposed to a regular Addr // method type Listener interface { + BaseListener + Accept() (CapableConn, error) +} + +// QListener is like listener but produce QCapableConn instead of CapableConn. +type QListener interface { + BaseListener + + Accept() (QCapableConn, error) +} + +// BaseListener is used to build `Lister` and `QListener` +type BaseListener interface { Close() error Addr() net.Addr Multiaddr() ma.Multiaddr @@ -109,5 +200,8 @@ type TransportNetwork interface { // local multiaddr and pick the *last* protocol registered with a proxy // transport, if any. Otherwise, it'll pick the transport registered to // handle the last protocol in the multiaddr. - AddTransport(t Transport) error + // + // Even if BaseTransport are accepted its needed to be able to cast to + // Transport or QTransport. + AddTransport(t BaseTransport) error }