dht_test.go 8.98 KB
Newer Older
1 2
package dht

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
3
import (
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
4
	"bytes"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
5 6 7 8
	"testing"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"

9
	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10 11 12 13 14 15 16 17 18 19 20 21 22
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"

	ci "github.com/jbenet/go-ipfs/crypto"
	inet "github.com/jbenet/go-ipfs/net"
	mux "github.com/jbenet/go-ipfs/net/mux"
	netservice "github.com/jbenet/go-ipfs/net/service"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"

	"fmt"
	"time"
)

23
func setupDHT(ctx context.Context, t *testing.T, p peer.Peer) *IpfsDHT {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
24 25
	peerstore := peer.NewPeerstore()

26
	dhts := netservice.NewService(ctx, nil) // nil handler for now, need to patch it
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
27
	net, err := inet.NewIpfsNetwork(ctx, p, peerstore, &mux.ProtocolMap{
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
28 29 30 31 32 33
		mux.ProtocolID_Routing: dhts,
	})
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
34
	d := NewDHT(ctx, p, peerstore, net, dhts, ds.NewMapDatastore())
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
35
	dhts.SetHandler(d)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
36 37 38
	return d
}

39
func setupDHTS(ctx context.Context, n int, t *testing.T) ([]ma.Multiaddr, []peer.Peer, []*IpfsDHT) {
40
	var addrs []ma.Multiaddr
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
41
	for i := 0; i < n; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
42 43 44 45 46 47 48
		a, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 5000+i))
		if err != nil {
			t.Fatal(err)
		}
		addrs = append(addrs, a)
	}

49
	var peers []peer.Peer
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
50
	for i := 0; i < n; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
51 52 53 54
		p := makePeer(addrs[i])
		peers = append(peers, p)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
55 56
	dhts := make([]*IpfsDHT, n)
	for i := 0; i < n; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
57
		dhts[i] = setupDHT(ctx, t, peers[i])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
58 59 60 61 62
	}

	return addrs, peers, dhts
}

63
func makePeer(addr ma.Multiaddr) peer.Peer {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
64 65 66 67
	sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
	if err != nil {
		panic(err)
	}
68
	p, err := peer.WithKeyPair(sk, pk)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
69 70 71
	if err != nil {
		panic(err)
	}
72
	p.AddAddress(addr)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
73 74 75 76
	return p
}

func TestPing(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
77
	// t.Skip("skipping test to debug another")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
78
	ctx := context.Background()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
79
	u.Debug = false
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
80 81 82 83 84 85 86 87 88 89 90 91
	addrA, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/2222")
	if err != nil {
		t.Fatal(err)
	}
	addrB, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/5678")
	if err != nil {
		t.Fatal(err)
	}

	peerA := makePeer(addrA)
	peerB := makePeer(addrB)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
92 93
	dhtA := setupDHT(ctx, t, peerA)
	dhtB := setupDHT(ctx, t, peerB)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
94

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
95 96
	defer dhtA.Close()
	defer dhtB.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
97 98
	defer dhtA.dialer.(inet.Network).Close()
	defer dhtB.dialer.(inet.Network).Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
99

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
100
	_, err = dhtA.Connect(ctx, peerB)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
101 102 103 104 105
	if err != nil {
		t.Fatal(err)
	}

	//Test that we can ping the node
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
106
	ctxT, _ := context.WithTimeout(ctx, 100*time.Millisecond)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
107
	err = dhtA.Ping(ctxT, peerB)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
108 109 110
	if err != nil {
		t.Fatal(err)
	}
111

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
112
	ctxT, _ = context.WithTimeout(ctx, 100*time.Millisecond)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
113
	err = dhtB.Ping(ctxT, peerA)
114 115 116
	if err != nil {
		t.Fatal(err)
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
117 118 119
}

func TestValueGetSet(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
120 121
	// t.Skip("skipping test to debug another")

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
122
	ctx := context.Background()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
123
	u.Debug = false
124
	addrA, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/11235")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
125 126 127
	if err != nil {
		t.Fatal(err)
	}
128
	addrB, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/15679")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
129 130 131 132 133 134 135
	if err != nil {
		t.Fatal(err)
	}

	peerA := makePeer(addrA)
	peerB := makePeer(addrB)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
136 137
	dhtA := setupDHT(ctx, t, peerA)
	dhtB := setupDHT(ctx, t, peerB)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
138

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
139 140
	defer dhtA.Close()
	defer dhtB.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
141 142
	defer dhtA.dialer.(inet.Network).Close()
	defer dhtB.dialer.(inet.Network).Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
143

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
144
	_, err = dhtA.Connect(ctx, peerB)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
145 146 147 148
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
149
	ctxT, _ := context.WithTimeout(ctx, time.Second)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
150
	dhtA.PutValue(ctxT, "hello", []byte("world"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
151

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
152
	ctxT, _ = context.WithTimeout(ctx, time.Second*2)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
153
	val, err := dhtA.GetValue(ctxT, "hello")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
154 155 156 157 158 159 160 161
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatalf("Expected 'world' got '%s'", string(val))
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
162
	ctxT, _ = context.WithTimeout(ctx, time.Second*2)
163 164 165 166 167 168 169 170
	val, err = dhtB.GetValue(ctxT, "hello")
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatalf("Expected 'world' got '%s'", string(val))
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
171 172
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
173 174
func TestProvides(t *testing.T) {
	// t.Skip("skipping test to debug another")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
175
	ctx := context.Background()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
176 177 178

	u.Debug = false

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
179
	_, peers, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
180 181
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
182
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
183
			defer dhts[i].dialer.(inet.Network).Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
184 185 186
		}
	}()

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
187
	_, err := dhts[0].Connect(ctx, peers[1])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
188 189 190 191
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
192
	_, err = dhts[1].Connect(ctx, peers[2])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
193 194 195 196
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
197
	_, err = dhts[1].Connect(ctx, peers[3])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	bits, err := dhts[3].getLocal(u.Key("hello"))
	if err != nil && bytes.Equal(bits, []byte("world")) {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
212
	err = dhts[3].Provide(ctx, u.Key("hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
213 214 215 216 217 218
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
219
	ctxT, _ := context.WithTimeout(ctx, time.Second)
Jeromy's avatar
Jeromy committed
220
	provchan := dhts[0].FindProvidersAsync(ctxT, u.Key("hello"), 1)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
221

Jeromy's avatar
Jeromy committed
222 223 224 225 226 227 228 229
	after := time.After(time.Second)
	select {
	case prov := <-provchan:
		if prov == nil {
			t.Fatal("Got back nil provider")
		}
	case <-after:
		t.Fatal("Did not get a provider back.")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
230 231 232
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
233 234 235
func TestProvidesAsync(t *testing.T) {
	// t.Skip("skipping test to debug another")

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
236
	ctx := context.Background()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
237 238
	u.Debug = false

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
239
	_, peers, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
240 241
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
242
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
243
			defer dhts[i].dialer.(inet.Network).Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
244 245 246
		}
	}()

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
247
	_, err := dhts[0].Connect(ctx, peers[1])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
248 249 250 251
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
252
	_, err = dhts[1].Connect(ctx, peers[2])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
253 254 255 256
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
257
	_, err = dhts[1].Connect(ctx, peers[3])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
258 259 260 261 262 263 264 265 266 267 268 269 270 271
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	bits, err := dhts[3].getLocal(u.Key("hello"))
	if err != nil && bytes.Equal(bits, []byte("world")) {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
272
	err = dhts[3].Provide(ctx, u.Key("hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
273 274 275 276 277 278
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
279 280
	ctxT, _ := context.WithTimeout(ctx, time.Millisecond*300)
	provs := dhts[0].FindProvidersAsync(ctxT, u.Key("hello"), 5)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
281
	select {
Jeromy's avatar
Jeromy committed
282 283 284 285 286 287 288
	case p, ok := <-provs:
		if !ok {
			t.Fatal("Provider channel was closed...")
		}
		if p == nil {
			t.Fatal("Got back nil provider!")
		}
289
		if !p.ID().Equal(dhts[3].self.ID()) {
290
			t.Fatalf("got a provider, but not the right one. %s", p)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
291
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
292
	case <-ctxT.Done():
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
293 294 295 296
		t.Fatal("Didnt get back providers")
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
297 298 299
func TestLayeredGet(t *testing.T) {
	// t.Skip("skipping test to debug another")

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
300
	ctx := context.Background()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
301
	u.Debug = false
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
302
	_, peers, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
303 304
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
305
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
306
			defer dhts[i].dialer.(inet.Network).Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
307 308 309
		}
	}()

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
310
	_, err := dhts[0].Connect(ctx, peers[1])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
311 312 313 314
	if err != nil {
		t.Fatalf("Failed to connect: %s", err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
315
	_, err = dhts[1].Connect(ctx, peers[2])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
316 317 318 319
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
320
	_, err = dhts[1].Connect(ctx, peers[3])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
321 322 323 324 325 326 327 328 329
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
330
	err = dhts[3].Provide(ctx, u.Key("hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
331 332 333 334 335 336
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
337
	ctxT, _ := context.WithTimeout(ctx, time.Second)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
338
	val, err := dhts[0].GetValue(ctxT, u.Key("hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
339 340 341 342 343 344 345 346 347 348 349 350 351
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatal("Got incorrect value.")
	}

}

func TestFindPeer(t *testing.T) {
	// t.Skip("skipping test to debug another")

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
352
	ctx := context.Background()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
353 354
	u.Debug = false

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
355
	_, peers, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
356 357
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
358
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
359
			dhts[i].dialer.(inet.Network).Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
360 361 362
		}
	}()

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
363
	_, err := dhts[0].Connect(ctx, peers[1])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
364 365 366 367
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
368
	_, err = dhts[1].Connect(ctx, peers[2])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
369 370 371 372
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
373
	_, err = dhts[1].Connect(ctx, peers[3])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
374 375 376 377
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
378
	ctxT, _ := context.WithTimeout(ctx, time.Second)
379
	p, err := dhts[0].FindPeer(ctxT, peers[2].ID())
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
380 381 382 383 384 385 386 387
	if err != nil {
		t.Fatal(err)
	}

	if p == nil {
		t.Fatal("Failed to find peer.")
	}

388
	if !p.ID().Equal(peers[2].ID()) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
389 390 391
		t.Fatal("Didnt find expected peer.")
	}
}
392 393 394 395

func TestConnectCollision(t *testing.T) {
	// t.Skip("skipping test to debug another")

396
	runTimes := 10
397

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
398 399
	for rtime := 0; rtime < runTimes; rtime++ {
		log.Notice("Running Time: ", rtime)
400

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
401 402
		ctx := context.Background()
		u.Debug = false
403
		addrA, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/11235")
404 405 406
		if err != nil {
			t.Fatal(err)
		}
407
		addrB, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/15679")
408 409 410 411
		if err != nil {
			t.Fatal(err)
		}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
		peerA := makePeer(addrA)
		peerB := makePeer(addrB)

		dhtA := setupDHT(ctx, t, peerA)
		dhtB := setupDHT(ctx, t, peerB)

		done := make(chan struct{})
		go func() {
			_, err = dhtA.Connect(ctx, peerB)
			if err != nil {
				t.Fatal(err)
			}
			done <- struct{}{}
		}()
		go func() {
			_, err = dhtB.Connect(ctx, peerA)
			if err != nil {
				t.Fatal(err)
			}
			done <- struct{}{}
		}()

		timeout := time.After(time.Second)
		select {
		case <-done:
		case <-timeout:
			t.Fatal("Timeout received!")
		}
		select {
		case <-done:
		case <-timeout:
			t.Fatal("Timeout received!")
		}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
446 447
		dhtA.Close()
		dhtB.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
448 449
		dhtA.dialer.(inet.Network).Close()
		dhtB.dialer.(inet.Network).Close()
450 451

		<-time.After(200 * time.Millisecond)
Jeromy's avatar
Jeromy committed
452
	}
453
}