// Self returns the local node's endpoint information. func (srv *Server) Self() *discover.Node { srv.lock.Lock() defer srv.lock.Unlock() // If the server's not running, return an empty node if !srv.running { return &discover.Node{IP: net.ParseIP("0.0.0.0")} } // If the node is running but discovery is off, manually assemble the node infos if srv.ntab == nil { // Inbound connections disabled, use zero address if srv.listener == nil { return &discover.Node{IP: net.ParseIP("0.0.0.0"), ID: discover.PubkeyID(&srv.PrivateKey.PublicKey)} } // Otherwise inject the listener address too addr := srv.listener.Addr().(*net.TCPAddr) return &discover.Node{ ID: discover.PubkeyID(&srv.PrivateKey.PublicKey), IP: addr.IP, TCP: uint16(addr.Port), } } // Otherwise return the live node infos return srv.ntab.Self() }
// Start starts running the server. // Servers can not be re-used after stopping. func (srv *Server) Start() (err error) { srv.lock.Lock() defer srv.lock.Unlock() if srv.running { return errors.New("server already running") } srv.running = true glog.V(logger.Info).Infoln("Starting Server") // static fields if srv.PrivateKey == nil { return fmt.Errorf("Server.PrivateKey must be set to a non-nil key") } if srv.newTransport == nil { srv.newTransport = newRLPX } if srv.Dialer == nil { srv.Dialer = &net.Dialer{Timeout: defaultDialTimeout} } srv.quit = make(chan struct{}) srv.addpeer = make(chan *conn) srv.delpeer = make(chan *Peer) srv.posthandshake = make(chan *conn) srv.addstatic = make(chan *discover.Node) srv.peerOp = make(chan peerOpFunc) srv.peerOpDone = make(chan struct{}) // node table if srv.Discovery { ntab, err := discover.ListenUDP(srv.PrivateKey, srv.ListenAddr, srv.NAT, srv.NodeDatabase) if err != nil { return err } srv.ntab = ntab } dynPeers := srv.MaxPeers / 2 if !srv.Discovery { dynPeers = 0 } dialer := newDialState(srv.StaticNodes, srv.ntab, dynPeers) // handshake srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: discover.PubkeyID(&srv.PrivateKey.PublicKey)} for _, p := range srv.Protocols { srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap()) } // listen/dial if srv.ListenAddr != "" { if err := srv.startListening(); err != nil { return err } } if srv.NoDial && srv.ListenAddr == "" { glog.V(logger.Warn).Infoln("I will be kind-of useless, neither dialing nor listening.") } srv.loopWG.Add(1) go srv.run(dialer) srv.running = true return nil }
func testEncHandshake(token []byte) error { type result struct { side string id discover.NodeID err error } var ( prv0, _ = crypto.GenerateKey() prv1, _ = crypto.GenerateKey() fd0, fd1 = net.Pipe() c0, c1 = newRLPX(fd0).(*rlpx), newRLPX(fd1).(*rlpx) output = make(chan result) ) go func() { r := result{side: "initiator"} defer func() { output <- r }() dest := &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey)} r.id, r.err = c0.doEncHandshake(prv0, dest) if r.err != nil { return } id1 := discover.PubkeyID(&prv1.PublicKey) if r.id != id1 { r.err = fmt.Errorf("remote ID mismatch: got %v, want: %v", r.id, id1) } }() go func() { r := result{side: "receiver"} defer func() { output <- r }() r.id, r.err = c1.doEncHandshake(prv1, nil) if r.err != nil { return } id0 := discover.PubkeyID(&prv0.PublicKey) if r.id != id0 { r.err = fmt.Errorf("remote ID mismatch: got %v, want: %v", r.id, id0) } }() // wait for results from both sides r1, r2 := <-output, <-output if r1.err != nil { return fmt.Errorf("%s side error: %v", r1.side, r1.err) } if r2.err != nil { return fmt.Errorf("%s side error: %v", r2.side, r2.err) } // compare derived secrets if !reflect.DeepEqual(c0.rw.egressMAC, c1.rw.ingressMAC) { return fmt.Errorf("egress mac mismatch:\n c0.rw: %#v\n c1.rw: %#v", c0.rw.egressMAC, c1.rw.ingressMAC) } if !reflect.DeepEqual(c0.rw.ingressMAC, c1.rw.egressMAC) { return fmt.Errorf("ingress mac mismatch:\n c0.rw: %#v\n c1.rw: %#v", c0.rw.ingressMAC, c1.rw.egressMAC) } if !reflect.DeepEqual(c0.rw.enc, c1.rw.enc) { return fmt.Errorf("enc cipher mismatch:\n c0.rw: %#v\n c1.rw: %#v", c0.rw.enc, c1.rw.enc) } if !reflect.DeepEqual(c0.rw.dec, c1.rw.dec) { return fmt.Errorf("dec cipher mismatch:\n c0.rw: %#v\n c1.rw: %#v", c0.rw.dec, c1.rw.dec) } return nil }
func TestServerSetupConn(t *testing.T) { id := randomID() srvkey := newkey() srvid := discover.PubkeyID(&srvkey.PublicKey) tests := []struct { dontstart bool tt *setupTransport flags connFlag dialDest *discover.Node wantCloseErr error wantCalls string }{ { dontstart: true, tt: &setupTransport{id: id}, wantCalls: "close,", wantCloseErr: errServerStopped, }, { tt: &setupTransport{id: id, encHandshakeErr: errors.New("read error")}, flags: inboundConn, wantCalls: "doEncHandshake,close,", wantCloseErr: errors.New("read error"), }, { tt: &setupTransport{id: id}, dialDest: &discover.Node{ID: randomID()}, flags: dynDialedConn, wantCalls: "doEncHandshake,close,", wantCloseErr: DiscUnexpectedIdentity, }, { tt: &setupTransport{id: id, phs: &protoHandshake{ID: randomID()}}, dialDest: &discover.Node{ID: id}, flags: dynDialedConn, wantCalls: "doEncHandshake,doProtoHandshake,close,", wantCloseErr: DiscUnexpectedIdentity, }, { tt: &setupTransport{id: id, protoHandshakeErr: errors.New("foo")}, dialDest: &discover.Node{ID: id}, flags: dynDialedConn, wantCalls: "doEncHandshake,doProtoHandshake,close,", wantCloseErr: errors.New("foo"), }, { tt: &setupTransport{id: srvid, phs: &protoHandshake{ID: srvid}}, flags: inboundConn, wantCalls: "doEncHandshake,close,", wantCloseErr: DiscSelf, }, { tt: &setupTransport{id: id, phs: &protoHandshake{ID: id}}, flags: inboundConn, wantCalls: "doEncHandshake,doProtoHandshake,close,", wantCloseErr: DiscUselessPeer, }, } for i, test := range tests { srv := &Server{ PrivateKey: srvkey, MaxPeers: 10, NoDial: true, Protocols: []Protocol{discard}, newTransport: func(fd net.Conn) transport { return test.tt }, } if !test.dontstart { if err := srv.Start(); err != nil { t.Fatalf("couldn't start server: %v", err) } } p1, _ := net.Pipe() srv.setupConn(p1, test.flags, test.dialDest) if !reflect.DeepEqual(test.tt.closeErr, test.wantCloseErr) { t.Errorf("test %d: close error mismatch: got %q, want %q", i, test.tt.closeErr, test.wantCloseErr) } if test.tt.calls != test.wantCalls { t.Errorf("test %d: calls mismatch: got %q, want %q", i, test.tt.calls, test.wantCalls) } } }
func TestProtocolHandshake(t *testing.T) { var ( prv0, _ = crypto.GenerateKey() node0 = &discover.Node{ID: discover.PubkeyID(&prv0.PublicKey), IP: net.IP{1, 2, 3, 4}, TCP: 33} hs0 = &protoHandshake{Version: 3, ID: node0.ID, Caps: []Cap{{"a", 0}, {"b", 2}}} prv1, _ = crypto.GenerateKey() node1 = &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey), IP: net.IP{5, 6, 7, 8}, TCP: 44} hs1 = &protoHandshake{Version: 3, ID: node1.ID, Caps: []Cap{{"c", 1}, {"d", 3}}} fd0, fd1 = net.Pipe() wg sync.WaitGroup ) wg.Add(2) go func() { defer wg.Done() rlpx := newRLPX(fd0) remid, err := rlpx.doEncHandshake(prv0, node1) if err != nil { t.Errorf("dial side enc handshake failed: %v", err) return } if remid != node1.ID { t.Errorf("dial side remote id mismatch: got %v, want %v", remid, node1.ID) return } phs, err := rlpx.doProtoHandshake(hs0) if err != nil { t.Errorf("dial side proto handshake error: %v", err) return } if !reflect.DeepEqual(phs, hs1) { t.Errorf("dial side proto handshake mismatch:\ngot: %s\nwant: %s\n", spew.Sdump(phs), spew.Sdump(hs1)) return } rlpx.close(DiscQuitting) }() go func() { defer wg.Done() rlpx := newRLPX(fd1) remid, err := rlpx.doEncHandshake(prv1, nil) if err != nil { t.Errorf("listen side enc handshake failed: %v", err) return } if remid != node0.ID { t.Errorf("listen side remote id mismatch: got %v, want %v", remid, node0.ID) return } phs, err := rlpx.doProtoHandshake(hs1) if err != nil { t.Errorf("listen side proto handshake error: %v", err) return } if !reflect.DeepEqual(phs, hs0) { t.Errorf("listen side proto handshake mismatch:\ngot: %s\nwant: %s\n", spew.Sdump(phs), spew.Sdump(hs0)) return } if err := ExpectMsg(rlpx, discMsg, []DiscReason{DiscQuitting}); err != nil { t.Errorf("error receiving disconnect: %v", err) } }() wg.Wait() }