mirror of
https://github.com/ipfs/kubo.git
synced 2026-03-06 08:47:52 +08:00
p2p/net/conn: use reuseport
This commit is contained in:
parent
911a3c90bc
commit
334f9d2102
@ -2,11 +2,14 @@ package conn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
|
||||
reuseport "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport"
|
||||
|
||||
peer "github.com/jbenet/go-ipfs/p2p/peer"
|
||||
debugerror "github.com/jbenet/go-ipfs/util/debugerror"
|
||||
@ -22,32 +25,7 @@ func (d *Dialer) String() string {
|
||||
// Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
|
||||
func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) {
|
||||
|
||||
_, _, err := manet.DialArgs(raddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
|
||||
return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr)
|
||||
}
|
||||
|
||||
if len(d.LocalAddrs) > 0 {
|
||||
laddrs := manet.AddrMatch(raddr, d.LocalAddrs)
|
||||
if len(laddrs) < 1 {
|
||||
return nil, debugerror.Errorf("No local address matches %s %s", raddr, d.LocalAddrs)
|
||||
}
|
||||
|
||||
// TODO pick with a good heuristic
|
||||
// we use a random one for now to prevent bad addresses from making nodes unreachable
|
||||
// with a random selection, multiple tries may work.
|
||||
// laddr := laddrs[rand.Intn(len(laddrs))]
|
||||
|
||||
// TODO: try to get reusing addr/ports to work.
|
||||
// d.Dialer.LocalAddr = laddr
|
||||
}
|
||||
|
||||
log.Debugf("%s dialing %s %s", d.LocalPeer, remote, raddr)
|
||||
maconn, err := d.Dialer.Dial(raddr)
|
||||
maconn, err := d.rawConnDial(ctx, raddr, remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -92,6 +70,78 @@ func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (
|
||||
return connOut, errOut
|
||||
}
|
||||
|
||||
// rawConnDial dials the underlying net.Conn + manet.Conns
|
||||
func (d *Dialer) rawConnDial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (manet.Conn, error) {
|
||||
|
||||
// before doing anything, check we're going to be able to dial.
|
||||
// we may not support the given address.
|
||||
_, _, err := manet.DialArgs(raddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
|
||||
return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr)
|
||||
}
|
||||
|
||||
// get local addr to use.
|
||||
laddr := pickLocalAddr(d.LocalAddrs, raddr)
|
||||
|
||||
log.Debugf("%s dialing %s -- %s --> %s", d.LocalPeer, remote, laddr, raddr)
|
||||
if laddr != nil {
|
||||
// dial using reuseport.Dialer, because we're probably reusing addrs.
|
||||
// this is optimistic, as the reuseDial may fail to bind the port.
|
||||
log.Debugf("trying to reuse: %s", laddr)
|
||||
if nconn, err := d.reuseDial(laddr, raddr); err == nil {
|
||||
// if it worked, wrap the raw net.Conn with our manet.Conn
|
||||
log.Debugf("reuse worked! %s %s %s", laddr, nconn.RemoteAddr(), nconn)
|
||||
return manet.WrapNetConn(nconn)
|
||||
}
|
||||
// if not, we fall back to regular Dial without a local addr specified.
|
||||
}
|
||||
|
||||
// no local addr, or failed to reuse. just dial straight with a new port.
|
||||
return d.Dialer.Dial(raddr)
|
||||
}
|
||||
|
||||
func (d *Dialer) reuseDial(laddr, raddr ma.Multiaddr) (net.Conn, error) {
|
||||
// give reuse.Dialer the manet.Dialer's Dialer.
|
||||
// (wow, Dialer should've so been an interface...)
|
||||
rd := reuseport.Dialer{d.Dialer.Dialer}
|
||||
|
||||
// get the local net.Addr manually
|
||||
var err error
|
||||
rd.D.LocalAddr, err = manet.ToNetAddr(laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// get the raddr dial args for rd.dial
|
||||
network, netraddr, err := manet.DialArgs(raddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// rd.Dial gets us a net.Conn with SO_REUSEPORT and SO_REUSEADDR set.
|
||||
return rd.Dial(network, netraddr)
|
||||
}
|
||||
|
||||
func pickLocalAddr(laddrs []ma.Multiaddr, raddr ma.Multiaddr) (laddr ma.Multiaddr) {
|
||||
if len(laddrs) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
laddrs = manet.AddrMatch(raddr, laddrs)
|
||||
if len(laddrs) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO pick with a good heuristic
|
||||
// we use a random one for now to prevent bad addresses from making nodes unreachable
|
||||
// with a random selection, multiple tries may work.
|
||||
return laddrs[rand.Intn(len(laddrs))]
|
||||
}
|
||||
|
||||
// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks.
|
||||
func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool {
|
||||
ap := a.Protocols()
|
||||
|
||||
@ -9,7 +9,9 @@ import (
|
||||
ctxgroup "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
|
||||
reuseport "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport"
|
||||
tec "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher"
|
||||
|
||||
ic "github.com/jbenet/go-ipfs/p2p/crypto"
|
||||
peer "github.com/jbenet/go-ipfs/p2p/peer"
|
||||
)
|
||||
@ -123,11 +125,23 @@ func (l *listener) Loggable() map[string]interface{} {
|
||||
// Listen listens on the particular multiaddr, with given peer and peerstore.
|
||||
func Listen(ctx context.Context, addr ma.Multiaddr, local peer.ID, sk ic.PrivKey) (Listener, error) {
|
||||
|
||||
ml, err := manet.Listen(addr)
|
||||
network, naddr, err := manet.DialArgs(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// _ := reuseport.Listen
|
||||
// ml, err := manet.Listen(addr)
|
||||
nl, err := reuseport.Listen(network, naddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to listen on %s: %s", addr, err)
|
||||
}
|
||||
|
||||
ml, err := manet.WrapNetListener(nl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l := &listener{
|
||||
Listener: ml,
|
||||
local: local,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user