diff --git a/btcd/rpcserver.go b/btcd/rpcserver.go index cae61050..520030fd 100644 --- a/btcd/rpcserver.go +++ b/btcd/rpcserver.go @@ -22,14 +22,14 @@ import ( // rpcServer holds the items the rpc server may need to access (config, // shutdown, main server, etc.) type rpcServer struct { - started bool - shutdown bool - server *server - wg sync.WaitGroup - rpcport string - username string - password string - listener net.Listener + started bool + shutdown bool + server *server + wg sync.WaitGroup + rpcport string + username string + password string + listeners []net.Listener } // Start is used by server.go to start the rpc listener. @@ -42,14 +42,16 @@ func (s *rpcServer) Start() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { jsonRpcRead(w, r, s) }) - listenAddr := net.JoinHostPort("", s.rpcport) - httpServer := &http.Server{Addr: listenAddr} - go func() { - log.Infof("[RPCS] RPC server listening on %s", s.listener.Addr()) - httpServer.Serve(s.listener) - s.wg.Done() - }() - s.wg.Add(1) + httpServer := &http.Server{} + for _, listener := range s.listeners { + go func(listener net.Listener) { + log.Infof("[RPCS] RPC server listening on %s", listener.Addr()) + httpServer.Serve(listener) + log.Tracef("[RPCS] RPC listener done for %s", listener.Addr()) + s.wg.Done() + }(listener) + s.wg.Add(1) + } s.started = true } @@ -60,10 +62,12 @@ func (s *rpcServer) Stop() error { return nil } log.Warnf("[RPCS] RPC server shutting down") - err := s.listener.Close() - if err != nil { - log.Errorf("[RPCS] Problem shutting down rpc: %v", err) - return err + for _, listener := range s.listeners { + err := listener.Close() + if err != nil { + log.Errorf("[RPCS] Problem shutting down rpc: %v", err) + return err + } } log.Infof("[RPCS] RPC server shutdown complete") s.wg.Wait() @@ -81,13 +85,26 @@ func newRpcServer(s *server) (*rpcServer, error) { rpc.username = cfg.RpcUser rpc.password = cfg.RpcPass - listenAddr := net.JoinHostPort("", rpc.rpcport) - listener, err := net.Listen("tcp", listenAddr) + // IPv4 listener. + var listeners []net.Listener + listenAddr4 := net.JoinHostPort("127.0.0.1", rpc.rpcport) + listener4, err := net.Listen("tcp4", listenAddr4) if err != nil { log.Errorf("[RPCS] Couldn't create listener: %v", err) return nil, err } - rpc.listener = listener + listeners = append(listeners, listener4) + + // IPv6 listener. + listenAddr6 := net.JoinHostPort("::1", rpc.rpcport) + listener6, err := net.Listen("tcp6", listenAddr6) + if err != nil { + log.Errorf("[RPCS] Couldn't create listener: %v", err) + return nil, err + } + listeners = append(listeners, listener6) + + rpc.listeners = listeners return &rpc, err } diff --git a/btcd/server.go b/btcd/server.go index 6cdffa84..7ae4093d 100644 --- a/btcd/server.go +++ b/btcd/server.go @@ -40,7 +40,7 @@ type broadcastMsg struct { // bitcoin peers. type server struct { nonce uint64 - listener net.Listener + listeners []net.Listener btcnet btcwire.BitcoinNet started bool shutdown bool @@ -162,10 +162,10 @@ func (s *server) handleBroadcastMsg(peers *list.List, bmsg *broadcastMsg) { // listenHandler is the main listener which accepts incoming connections for the // server. It must be run as a goroutine. -func (s *server) listenHandler() { - log.Infof("[SRVR] Server listening on %s", s.listener.Addr()) +func (s *server) listenHandler(listener net.Listener) { + log.Infof("[SRVR] Server listening on %s", listener.Addr()) for !s.shutdown { - conn, err := s.listener.Accept() + conn, err := listener.Accept() if err != nil { // Only log the error if we're not forcibly shutting down. if !s.shutdown { @@ -176,14 +176,14 @@ func (s *server) listenHandler() { s.AddPeer(newPeer(s, conn, true, false)) } s.wg.Done() - log.Tracef("[SRVR] Listener handler done for %s", s.listener.Addr()) + log.Tracef("[SRVR] Listener handler done for %s", listener.Addr()) } // peerHandler is used to handle peer operations such as adding and removing // peers to and from the server, banning peers, and broadcasting messages to // peers. It must be run a a goroutine. func (s *server) peerHandler() { - log.Tracef("[SRVR] Starting peer handler for %s", s.listener.Addr()) + log.Tracef("[SRVR] Starting peer handler") peers := list.New() bannedPeers := make(map[string]time.Time) @@ -218,7 +218,7 @@ func (s *server) peerHandler() { } } s.wg.Done() - log.Tracef("[SRVR] Peer handler done on %s", s.listener.Addr()) + log.Tracef("[SRVR] Peer handler done") } // AddPeer adds a new peer that has already been connected to the server. @@ -283,9 +283,12 @@ func (s *server) Start() { } log.Trace("[SRVR] Starting server") - go s.listenHandler() + for _, listener := range s.listeners { + go s.listenHandler(listener) + s.wg.Add(1) + } go s.peerHandler() - s.wg.Add(2) + s.wg.Add(1) s.addrManager.Start() s.blockManager.Start() if !cfg.DisableRpc { @@ -305,15 +308,17 @@ func (s *server) Stop() error { log.Warnf("[SRVR] Server shutting down") s.shutdown = true - s.quit <- true + close(s.quit) if !cfg.DisableRpc { s.rpcServer.Stop() } s.addrManager.Stop() s.blockManager.Stop() - err := s.listener.Close() - if err != nil { - return err + for _, listener := range s.listeners { + err := listener.Close() + if err != nil { + return err + } } return nil } @@ -374,14 +379,24 @@ func newServer(addr string, db btcdb.Db, btcnet btcwire.BitcoinNet) (*server, er return nil, err } - listener, err := net.Listen("tcp", addr) + // IPv4 listener. + var listeners []net.Listener + listener4, err := net.Listen("tcp4", addr) if err != nil { return nil, err } + listeners = append(listeners, listener4) + + // IPv6 listener. + listener6, err := net.Listen("tcp6", addr) + if err != nil { + return nil, err + } + listeners = append(listeners, listener6) s := server{ nonce: nonce, - listener: listener, + listeners: listeners, btcnet: btcnet, addrManager: NewAddrManager(), newPeers: make(chan *peer, cfg.MaxPeers),