tcp.go 3.06 KB
Newer Older
1 2 3 4
package tcp

import (
	"context"
Steven Allen's avatar
Steven Allen committed
5
	"time"
6 7

	logging "github.com/ipfs/go-log"
8
	peer "github.com/libp2p/go-libp2p-peer"
9
	tpt "github.com/libp2p/go-libp2p-transport"
10 11
	tptu "github.com/libp2p/go-libp2p-transport-upgrader"
	rtpt "github.com/libp2p/go-reuseport-transport"
Jeromy's avatar
Jeromy committed
12 13
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr-net"
14 15 16
	mafmt "github.com/whyrusleeping/mafmt"
)

Steven Allen's avatar
Steven Allen committed
17 18 19 20
// DefaultConnectTimeout is the (default) maximum amount of time the TCP
// transport will spend on the initial TCP connect before giving up.
var DefaultConnectTimeout = 5 * time.Second

21 22
var log = logging.Logger("tcp-tpt")

23
// TcpTransport is the TCP transport.
24
type TcpTransport struct {
25 26 27
	// Connection upgrader for upgrading insecure stream connections to
	// secure multiplex connections.
	Upgrader *tptu.Upgrader
28

29 30 31
	// Explicitly disable reuseport.
	DisableReuseport bool

Steven Allen's avatar
Steven Allen committed
32 33 34
	// TCP connect timeout
	ConnectTimeout time.Duration

35
	reuse rtpt.Transport
36 37
}

38 39
var _ tpt.Transport = &TcpTransport{}

40 41
// NewTCPTransport creates a tcp transport object that tracks dialers and listeners
// created. It represents an entire tcp stack (though it might not necessarily be)
42
func NewTCPTransport(upgrader *tptu.Upgrader) *TcpTransport {
Steven Allen's avatar
Steven Allen committed
43
	return &TcpTransport{Upgrader: upgrader, ConnectTimeout: DefaultConnectTimeout}
44 45
}

46 47 48 49
// CanDial returns true if this transport believes it can dial the given
// multiaddr.
func (t *TcpTransport) CanDial(addr ma.Multiaddr) bool {
	return mafmt.TCP.Matches(addr)
50 51
}

52
func (t *TcpTransport) maDial(ctx context.Context, raddr ma.Multiaddr) (manet.Conn, error) {
Steven Allen's avatar
Steven Allen committed
53 54 55 56 57 58 59 60 61 62
	// Apply the deadline iff applicable
	if t.ConnectTimeout > 0 {
		deadline := time.Now().Add(t.ConnectTimeout)
		if d, ok := ctx.Deadline(); !ok || deadline.Before(d) {
			var cancel func()
			ctx, cancel = context.WithDeadline(ctx, deadline)
			defer cancel()
		}
	}

63 64
	if t.UseReuseport() {
		return t.reuse.DialContext(ctx, raddr)
65
	}
66 67
	var d manet.Dialer
	return d.DialContext(ctx, raddr)
68 69
}

70 71 72
// Dial dials the peer at the remote address.
func (t *TcpTransport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tpt.Conn, error) {
	conn, err := t.maDial(ctx, raddr)
73
	if err != nil {
74
		return nil, err
75
	}
76
	return t.Upgrader.UpgradeOutbound(ctx, t, conn, p)
77 78
}

79 80 81
// UseReuseport returns true if reuseport is enabled and available.
func (t *TcpTransport) UseReuseport() bool {
	return !t.DisableReuseport && ReuseportIsAvailable()
82 83
}

84 85 86
func (t *TcpTransport) maListen(laddr ma.Multiaddr) (manet.Listener, error) {
	if t.UseReuseport() {
		return t.reuse.Listen(laddr)
87
	}
88
	return manet.Listen(laddr)
89 90
}

91 92 93
// Listen listens on the given multiaddr.
func (t *TcpTransport) Listen(laddr ma.Multiaddr) (tpt.Listener, error) {
	list, err := t.maListen(laddr)
94 95 96
	if err != nil {
		return nil, err
	}
97
	return t.Upgrader.UpgradeListener(t, list), nil
98 99
}

100 101 102
// Protocols returns the list of terminal protocols this transport can dial.
func (t *TcpTransport) Protocols() []int {
	return []int{ma.P_TCP}
103 104
}

105 106 107
// Proxy always returns false for the TCP transport.
func (t *TcpTransport) Proxy() bool {
	return false
108 109
}

110 111
func (t *TcpTransport) String() string {
	return "TCP"
112
}