transport_test.go 5.72 KB
Newer Older
Steven Allen's avatar
Steven Allen committed
1 2 3
package tcpreuse

import (
Steven Allen's avatar
Steven Allen committed
4
	"net"
Steven Allen's avatar
Steven Allen committed
5 6 7
	"testing"

	ma "github.com/multiformats/go-multiaddr"
8
	manet "github.com/multiformats/go-multiaddr/net"
Steven Allen's avatar
Steven Allen committed
9 10
)

Steven Allen's avatar
Steven Allen committed
11 12 13 14
var loopbackV4, _ = ma.NewMultiaddr("/ip4/127.0.0.1/tcp/0")
var loopbackV6, _ = ma.NewMultiaddr("/ip6/::1/tcp/0")
var unspecV6, _ = ma.NewMultiaddr("/ip6/::/tcp/0")
var unspecV4, _ = ma.NewMultiaddr("/ip4/0.0.0.0/tcp/0")
Steven Allen's avatar
Steven Allen committed
15

Steven Allen's avatar
Steven Allen committed
16 17
var globalV4 ma.Multiaddr
var globalV6 ma.Multiaddr
Steven Allen's avatar
Steven Allen committed
18 19 20

func init() {
	addrs, err := manet.InterfaceMultiaddrs()
Steven Allen's avatar
Steven Allen committed
21
	if err != nil {
Steven Allen's avatar
Steven Allen committed
22
		return
Steven Allen's avatar
Steven Allen committed
23
	}
Steven Allen's avatar
Steven Allen committed
24 25 26
	for _, addr := range addrs {
		if !manet.IsIP6LinkLocal(addr) && !manet.IsIPLoopback(addr) {
			tcp, _ := ma.NewMultiaddr("/tcp/0")
Steven Allen's avatar
Steven Allen committed
27 28 29 30 31 32 33 34 35 36
			switch addr.Protocols()[0].Code {
			case ma.P_IP4:
				if globalV4 == nil {
					globalV4 = addr.Encapsulate(tcp)
				}
			case ma.P_IP6:
				if globalV6 == nil {
					globalV6 = addr.Encapsulate(tcp)
				}
			}
Steven Allen's avatar
Steven Allen committed
37 38 39
		}
	}
}
Steven Allen's avatar
Steven Allen committed
40

Will's avatar
Will committed
41
func acceptOne(t *testing.T, listener manet.Listener) <-chan interface{} {
Steven Allen's avatar
Steven Allen committed
42
	t.Helper()
Will's avatar
Will committed
43
	done := make(chan interface{}, 1)
Steven Allen's avatar
Steven Allen committed
44 45
	go func() {
		defer close(done)
Will's avatar
Will committed
46
		done <- nil
Steven Allen's avatar
Steven Allen committed
47
		c, err := listener.Accept()
Steven Allen's avatar
Steven Allen committed
48
		if err != nil {
Steven Allen's avatar
Steven Allen committed
49 50
			t.Error(err)
			return
Steven Allen's avatar
Steven Allen committed
51 52 53
		}
		c.Close()
	}()
Will's avatar
Will committed
54
	<-done
Steven Allen's avatar
Steven Allen committed
55 56 57 58 59
	return done
}

func dialOne(t *testing.T, tr *Transport, listener manet.Listener, expected ...int) int {
	t.Helper()
Steven Allen's avatar
Steven Allen committed
60

Steven Allen's avatar
Steven Allen committed
61 62
	done := acceptOne(t, listener)
	c, err := tr.Dial(listener.Multiaddr())
Steven Allen's avatar
Steven Allen committed
63 64 65
	if err != nil {
		t.Fatal(err)
	}
Steven Allen's avatar
Steven Allen committed
66
	port := c.LocalAddr().(*net.TCPAddr).Port
Steven Allen's avatar
Steven Allen committed
67 68
	<-done
	c.Close()
Steven Allen's avatar
Steven Allen committed
69 70 71 72 73 74 75 76
	if len(expected) == 0 {
		return port
	}
	for _, p := range expected {
		if p == port {
			return port
		}
	}
Will's avatar
Will committed
77
	t.Errorf("dialed %s from %v. expected to dial from port %v", listener.Multiaddr(), c.LocalAddr(), expected)
Steven Allen's avatar
Steven Allen committed
78 79
	return 0
}
Steven Allen's avatar
Steven Allen committed
80

Steven Allen's avatar
Steven Allen committed
81 82 83
func TestNoneAndSingle(t *testing.T) {
	var trA Transport
	var trB Transport
Steven Allen's avatar
Steven Allen committed
84
	listenerA, err := trA.Listen(loopbackV4)
Steven Allen's avatar
Steven Allen committed
85 86 87
	if err != nil {
		t.Fatal(err)
	}
Steven Allen's avatar
Steven Allen committed
88
	defer listenerA.Close()
Steven Allen's avatar
Steven Allen committed
89

Steven Allen's avatar
Steven Allen committed
90
	dialOne(t, &trB, listenerA)
Steven Allen's avatar
Steven Allen committed
91

Steven Allen's avatar
Steven Allen committed
92
	listenerB, err := trB.Listen(loopbackV4)
Steven Allen's avatar
Steven Allen committed
93 94 95
	if err != nil {
		t.Fatal(err)
	}
Steven Allen's avatar
Steven Allen committed
96 97 98
	defer listenerB.Close()

	dialOne(t, &trB, listenerA, listenerB.Addr().(*net.TCPAddr).Port)
Steven Allen's avatar
Steven Allen committed
99
}
Steven Allen's avatar
Steven Allen committed
100 101 102 103

func TestTwoLocal(t *testing.T) {
	var trA Transport
	var trB Transport
Steven Allen's avatar
Steven Allen committed
104
	listenerA, err := trA.Listen(loopbackV4)
Steven Allen's avatar
Steven Allen committed
105 106 107 108 109
	if err != nil {
		t.Fatal(err)
	}
	defer listenerA.Close()

Steven Allen's avatar
Steven Allen committed
110
	listenerB1, err := trB.Listen(loopbackV4)
Steven Allen's avatar
Steven Allen committed
111 112 113 114 115
	if err != nil {
		t.Fatal(err)
	}
	defer listenerB1.Close()

Steven Allen's avatar
Steven Allen committed
116
	listenerB2, err := trB.Listen(loopbackV4)
Steven Allen's avatar
Steven Allen committed
117 118 119 120 121
	if err != nil {
		t.Fatal(err)
	}
	defer listenerB2.Close()

Steven Allen's avatar
Steven Allen committed
122 123 124 125
	dialOne(t, &trB, listenerA,
		listenerB1.Addr().(*net.TCPAddr).Port,
		listenerB2.Addr().(*net.TCPAddr).Port)
}
Steven Allen's avatar
Steven Allen committed
126

Steven Allen's avatar
Steven Allen committed
127 128 129
func TestGlobalPreferenceV4(t *testing.T) {
	if globalV4 == nil {
		t.Skip("no global IPv4 addresses configured")
Steven Allen's avatar
Steven Allen committed
130
		return
Steven Allen's avatar
Steven Allen committed
131
	}
Will's avatar
Will committed
132
	t.Logf("when listening on %v, should prefer %v over %v", loopbackV4, loopbackV4, globalV4)
Steven Allen's avatar
Steven Allen committed
133
	testPrefer(t, loopbackV4, loopbackV4, globalV4)
Will's avatar
Will committed
134
	t.Logf("when listening on %v, should prefer %v over %v", loopbackV4, unspecV4, globalV4)
Steven Allen's avatar
Steven Allen committed
135
	testPrefer(t, loopbackV4, unspecV4, globalV4)
Steven Allen's avatar
Steven Allen committed
136

Will's avatar
Will committed
137
	t.Logf("when listening on %v, should prefer %v over %v", globalV4, unspecV4, loopbackV4)
Steven Allen's avatar
Steven Allen committed
138 139 140 141 142 143 144 145 146 147 148 149
	testPrefer(t, globalV4, unspecV4, loopbackV4)
}

func TestGlobalPreferenceV6(t *testing.T) {
	if globalV6 == nil {
		t.Skip("no global IPv6 addresses configured")
		return
	}
	testPrefer(t, loopbackV6, loopbackV6, globalV6)
	testPrefer(t, loopbackV6, unspecV6, globalV6)

	testPrefer(t, globalV6, unspecV6, loopbackV6)
Steven Allen's avatar
Steven Allen committed
150
}
151

Steven Allen's avatar
Steven Allen committed
152
func TestLoopbackPreference(t *testing.T) {
Steven Allen's avatar
Steven Allen committed
153 154
	testPrefer(t, loopbackV4, loopbackV4, unspecV4)
	testPrefer(t, loopbackV6, loopbackV6, unspecV6)
Steven Allen's avatar
Steven Allen committed
155 156 157
}

func testPrefer(t *testing.T, listen, prefer, avoid ma.Multiaddr) {
158 159
	var trA Transport
	var trB Transport
Steven Allen's avatar
Steven Allen committed
160
	listenerA, err := trA.Listen(listen)
161 162 163 164 165
	if err != nil {
		t.Fatal(err)
	}
	defer listenerA.Close()

Steven Allen's avatar
Steven Allen committed
166
	listenerB1, err := trB.Listen(avoid)
167 168 169 170 171
	if err != nil {
		t.Fatal(err)
	}
	defer listenerB1.Close()

Steven Allen's avatar
Steven Allen committed
172 173 174
	dialOne(t, &trB, listenerA, listenerB1.Addr().(*net.TCPAddr).Port)

	listenerB2, err := trB.Listen(prefer)
175 176 177 178 179
	if err != nil {
		t.Fatal(err)
	}
	defer listenerB2.Close()

Steven Allen's avatar
Steven Allen committed
180 181 182 183 184 185 186 187
	dialOne(t, &trB, listenerA, listenerB2.Addr().(*net.TCPAddr).Port)

	// Closing the listener should reset the dialer.
	listenerB2.Close()

	dialOne(t, &trB, listenerA, listenerB1.Addr().(*net.TCPAddr).Port)
}

Steven Allen's avatar
Steven Allen committed
188 189 190 191 192
func TestV6V4(t *testing.T) {
	testUseFirst(t, loopbackV4, loopbackV4, loopbackV6)
	testUseFirst(t, loopbackV6, loopbackV6, loopbackV4)
}

Steven Allen's avatar
Steven Allen committed
193
func TestGlobalToGlobal(t *testing.T) {
Steven Allen's avatar
Steven Allen committed
194 195
	if globalV4 == nil {
		t.Skip("no globalV4 addresses configured")
Steven Allen's avatar
Steven Allen committed
196 197
		return
	}
Steven Allen's avatar
Steven Allen committed
198 199 200
	testUseFirst(t, globalV4, globalV4, loopbackV4)
	testUseFirst(t, globalV6, globalV6, loopbackV6)
}
Steven Allen's avatar
Steven Allen committed
201

Steven Allen's avatar
Steven Allen committed
202
func testUseFirst(t *testing.T, listen, use, never ma.Multiaddr) {
Steven Allen's avatar
Steven Allen committed
203 204
	var trA Transport
	var trB Transport
Steven Allen's avatar
Steven Allen committed
205
	listenerA, err := trA.Listen(globalV4)
Steven Allen's avatar
Steven Allen committed
206 207 208 209
	if err != nil {
		t.Fatal(err)
	}
	defer listenerA.Close()
210

Steven Allen's avatar
Steven Allen committed
211
	listenerB1, err := trB.Listen(loopbackV4)
212 213 214
	if err != nil {
		t.Fatal(err)
	}
Steven Allen's avatar
Steven Allen committed
215 216 217 218 219
	defer listenerB1.Close()

	// It works (random port)
	dialOne(t, &trB, listenerA)

Steven Allen's avatar
Steven Allen committed
220
	listenerB2, err := trB.Listen(globalV4)
Steven Allen's avatar
Steven Allen committed
221 222
	if err != nil {
		t.Fatal(err)
223
	}
Steven Allen's avatar
Steven Allen committed
224 225
	defer listenerB2.Close()

Steven Allen's avatar
Steven Allen committed
226
	// Uses globalV4 port.
Steven Allen's avatar
Steven Allen committed
227
	dialOne(t, &trB, listenerA, listenerB2.Addr().(*net.TCPAddr).Port)
228 229

	// Closing the listener should reset the dialer.
Steven Allen's avatar
Steven Allen committed
230
	listenerB2.Close()
231

Steven Allen's avatar
Steven Allen committed
232 233 234 235 236
	// It still works.
	dialOne(t, &trB, listenerA)
}

func TestDuplicateGlobal(t *testing.T) {
Steven Allen's avatar
Steven Allen committed
237 238
	if globalV4 == nil {
		t.Skip("no globalV4 addresses configured")
Steven Allen's avatar
Steven Allen committed
239 240 241 242 243
		return
	}

	var trA Transport
	var trB Transport
Steven Allen's avatar
Steven Allen committed
244
	listenerA, err := trA.Listen(globalV4)
Steven Allen's avatar
Steven Allen committed
245 246 247 248
	if err != nil {
		t.Fatal(err)
	}
	defer listenerA.Close()
249

Steven Allen's avatar
Steven Allen committed
250
	listenerB1, err := trB.Listen(globalV4)
251 252 253
	if err != nil {
		t.Fatal(err)
	}
Steven Allen's avatar
Steven Allen committed
254 255
	defer listenerB1.Close()

Steven Allen's avatar
Steven Allen committed
256
	listenerB2, err := trB.Listen(globalV4)
Steven Allen's avatar
Steven Allen committed
257 258 259 260 261 262 263 264 265 266 267
	if err != nil {
		t.Fatal(err)
	}
	defer listenerB2.Close()

	// Check which port we're using
	port := dialOne(t, &trB, listenerA)

	// Check consistency
	for i := 0; i < 10; i++ {
		dialOne(t, &trB, listenerA, port)
268 269
	}
}