// managedConnectNewPeer connects to peers >= v1.0.0. The peer is added as a // node and a peer. The peer is only added if a nil error is returned. func (g *Gateway) managedConnectNewPeer(conn net.Conn, remoteVersion string, remoteAddr modules.NetAddress) error { g.mu.RLock() port := g.port g.mu.RUnlock() // Send our dialable address to the peer so they can dial us back should we // disconnect. err := connectPortHandshake(conn, port) if err != nil { return err } g.mu.Lock() defer g.mu.Unlock() err = g.addNode(remoteAddr) if err != nil && err != errNodeExists { return err } err = g.save() if err != nil { return fmt.Errorf("error saving node list: %v", err) } g.addPeer(&peer{ Peer: modules.Peer{ NetAddress: remoteAddr, Inbound: false, Version: remoteVersion, }, sess: muxado.Client(conn), }) return nil }
// managedConnectNewPeer connects to peers >= v1.0.0. The peer is added as a // node and a peer. The peer is only added if a nil error is returned. func (g *Gateway) managedConnectNewPeer(conn net.Conn, remoteVersion string, remoteAddr modules.NetAddress) error { g.mu.RLock() port := g.port g.mu.RUnlock() // Send our dialable address to the peer so they can dial us back should we // disconnect. err := connectPortHandshake(conn, port) if err != nil { return err } // Attempt to add the peer to the node list. If the add is successful and // the address is a local address, mark the peer as a local peer. local := false err = g.managedAddUntrustedNode(remoteAddr) if err != nil && remoteAddr.IsLocal() { local = true } g.mu.Lock() defer g.mu.Unlock() g.addPeer(&peer{ Peer: modules.Peer{ Inbound: false, Local: local, NetAddress: remoteAddr, Version: remoteVersion, }, sess: muxado.Client(conn), }) return nil }
// TestRandomInbountPeer checks that randomOutboundPeer returns the correct // peer. func TestRandomOutboundPeer(t *testing.T) { if testing.Short() { t.SkipNow() } g := newTestingGateway("TestRandomInboundPeer", t) defer g.Close() g.mu.Lock() defer g.mu.Unlock() _, err := g.randomOutboundPeer() if err != errNoPeers { t.Fatal("expected errNoPeers, got", err) } g.addPeer(&peer{ Peer: modules.Peer{ NetAddress: "foo.com:123", Inbound: false, }, sess: muxado.Client(new(dummyConn)), }) if len(g.peers) != 1 { t.Fatal("gateway did not add peer") } addr, err := g.randomOutboundPeer() if err != nil || addr != "foo.com:123" { t.Fatal("gateway did not select random peer") } }
// TestAddPeer tries adding a peer to the gateway. func TestAddPeer(t *testing.T) { if testing.Short() { t.SkipNow() } g := newTestingGateway("TestAddPeer", t) defer g.Close() g.mu.Lock() defer g.mu.Unlock() g.addPeer(&peer{ Peer: modules.Peer{ NetAddress: "foo.com:123", }, sess: muxado.Client(new(dummyConn)), }) if len(g.peers) != 1 { t.Fatal("gateway did not add peer") } }
// TestDisconnect checks that calls to gateway.Disconnect correctly disconnect // and remove peers from the gateway. func TestDisconnect(t *testing.T) { if testing.Short() { t.SkipNow() } g := newTestingGateway("TestDisconnect", t) defer g.Close() if err := g.Disconnect("bar.com:123"); err == nil { t.Fatal("disconnect removed unconnected peer") } // dummy listener to accept connection l, err := net.Listen("tcp", "localhost:0") if err != nil { t.Fatal("couldn't start listener:", err) } go func() { _, err := l.Accept() if err != nil { panic(err) } }() // skip standard connection protocol conn, err := net.Dial("tcp", l.Addr().String()) if err != nil { t.Fatal("dial failed:", err) } g.mu.Lock() g.addPeer(&peer{ Peer: modules.Peer{ NetAddress: "foo.com:123", }, sess: muxado.Client(conn), }) g.mu.Unlock() if err := g.Disconnect("foo.com:123"); err != nil { t.Fatal("disconnect failed:", err) } }
// managedConnectOldPeer connects to peers < v1.0.0. The peer is added as a // node and a peer. The peer is only added if a nil error is returned. func (g *Gateway) managedConnectOldPeer(conn net.Conn, remoteVersion string, remoteAddr modules.NetAddress) error { // Attempt to add the peer to the node list. If the add is successful and // the address is a local address, mark the peer as a local peer. local := false err := g.managedAddUntrustedNode(remoteAddr) if err != nil && remoteAddr.IsLocal() { local = true } g.mu.Lock() defer g.mu.Unlock() g.addPeer(&peer{ Peer: modules.Peer{ Inbound: false, Local: local, NetAddress: remoteAddr, Version: remoteVersion, }, sess: muxado.Client(conn), }) return nil }
// managedConnectOldPeer connects to peers < v1.0.0. The peer is added as a // node and a peer. The peer is only added if a nil error is returned. func (g *Gateway) managedConnectOldPeer(conn net.Conn, remoteVersion string, remoteAddr modules.NetAddress) error { g.mu.Lock() defer g.mu.Unlock() err := g.addNode(remoteAddr) if err != nil && err != errNodeExists { return err } err = g.save() if err != nil { return fmt.Errorf("error saving node list: %v", err) } g.addPeer(&peer{ Peer: modules.Peer{ NetAddress: remoteAddr, Inbound: false, Version: remoteVersion, }, sess: muxado.Client(conn), }) return nil }
// TestListen is a general test probling the connection listener. func TestListen(t *testing.T) { if testing.Short() { t.SkipNow() } g := newTestingGateway("TestListen", t) defer g.Close() // compliant connect with old version conn, err := net.Dial("tcp", string(g.Address())) if err != nil { t.Fatal("dial failed:", err) } addr := modules.NetAddress(conn.LocalAddr().String()) ack, err := connectVersionHandshake(conn, "0.1") if err != errPeerRejectedConn { t.Fatal(err) } if ack != "" { t.Fatal("gateway should have rejected old version") } for i := 0; i < 10; i++ { g.mu.RLock() _, ok := g.peers[addr] g.mu.RUnlock() if ok { t.Fatal("gateway should not have added an old peer") } time.Sleep(20 * time.Millisecond) } // a simple 'conn.Close' would not obey the muxado disconnect protocol muxado.Client(conn).Close() // compliant connect with invalid port conn, err = net.Dial("tcp", string(g.Address())) if err != nil { t.Fatal("dial failed:", err) } addr = modules.NetAddress(conn.LocalAddr().String()) ack, err = connectVersionHandshake(conn, build.Version) if err != nil { t.Fatal(err) } if ack != build.Version { t.Fatal("gateway should have given ack") } err = connectPortHandshake(conn, "0") if err != nil { t.Fatal(err) } for i := 0; i < 10; i++ { g.mu.RLock() _, ok := g.peers[addr] g.mu.RUnlock() if ok { t.Fatal("gateway should not have added a peer with an invalid port") } time.Sleep(20 * time.Millisecond) } // a simple 'conn.Close' would not obey the muxado disconnect protocol muxado.Client(conn).Close() // compliant connect conn, err = net.Dial("tcp", string(g.Address())) if err != nil { t.Fatal("dial failed:", err) } addr = modules.NetAddress(conn.LocalAddr().String()) ack, err = connectVersionHandshake(conn, build.Version) if err != nil { t.Fatal(err) } if ack != build.Version { t.Fatal("gateway should have given ack") } err = connectPortHandshake(conn, addr.Port()) if err != nil { t.Fatal(err) } // g should add the peer var ok bool for !ok { g.mu.RLock() _, ok = g.peers[addr] g.mu.RUnlock() } muxado.Client(conn).Close() // g should remove the peer for ok { g.mu.RLock() _, ok = g.peers[addr] g.mu.RUnlock() } // uncompliant connect conn, err = net.Dial("tcp", string(g.Address())) if err != nil { t.Fatal("dial failed:", err) } if _, err := conn.Write([]byte("missing length prefix")); err != nil { t.Fatal("couldn't write malformed header") } // g should have closed the connection if n, err := conn.Write([]byte("closed")); err != nil && n > 0 { t.Error("write succeeded after closed connection") } }