Make IPv4 and IPv6 listen on different sockets.

This commit implements support for listening on multiple sockets and
changes the default listen code to use one socket per address family (IPv4
and IPv6).

In addition, it changes the default listen binding for the RPC server to
localhost so only local clients can connect to it.

There need to be several options added to allow customization of these
settings and those will be in future commits.

Fixes #3.
This commit is contained in:
Dave Collins 2013-08-07 10:38:39 -05:00
parent c526c3af59
commit ca8496e66d
2 changed files with 70 additions and 38 deletions

View file

@ -22,14 +22,14 @@ import (
// rpcServer holds the items the rpc server may need to access (config, // rpcServer holds the items the rpc server may need to access (config,
// shutdown, main server, etc.) // shutdown, main server, etc.)
type rpcServer struct { type rpcServer struct {
started bool started bool
shutdown bool shutdown bool
server *server server *server
wg sync.WaitGroup wg sync.WaitGroup
rpcport string rpcport string
username string username string
password string password string
listener net.Listener listeners []net.Listener
} }
// Start is used by server.go to start the rpc 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) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
jsonRpcRead(w, r, s) jsonRpcRead(w, r, s)
}) })
listenAddr := net.JoinHostPort("", s.rpcport) httpServer := &http.Server{}
httpServer := &http.Server{Addr: listenAddr} for _, listener := range s.listeners {
go func() { go func(listener net.Listener) {
log.Infof("[RPCS] RPC server listening on %s", s.listener.Addr()) log.Infof("[RPCS] RPC server listening on %s", listener.Addr())
httpServer.Serve(s.listener) httpServer.Serve(listener)
s.wg.Done() log.Tracef("[RPCS] RPC listener done for %s", listener.Addr())
}() s.wg.Done()
s.wg.Add(1) }(listener)
s.wg.Add(1)
}
s.started = true s.started = true
} }
@ -60,10 +62,12 @@ func (s *rpcServer) Stop() error {
return nil return nil
} }
log.Warnf("[RPCS] RPC server shutting down") log.Warnf("[RPCS] RPC server shutting down")
err := s.listener.Close() for _, listener := range s.listeners {
if err != nil { err := listener.Close()
log.Errorf("[RPCS] Problem shutting down rpc: %v", err) if err != nil {
return err log.Errorf("[RPCS] Problem shutting down rpc: %v", err)
return err
}
} }
log.Infof("[RPCS] RPC server shutdown complete") log.Infof("[RPCS] RPC server shutdown complete")
s.wg.Wait() s.wg.Wait()
@ -81,13 +85,26 @@ func newRpcServer(s *server) (*rpcServer, error) {
rpc.username = cfg.RpcUser rpc.username = cfg.RpcUser
rpc.password = cfg.RpcPass rpc.password = cfg.RpcPass
listenAddr := net.JoinHostPort("", rpc.rpcport) // IPv4 listener.
listener, err := net.Listen("tcp", listenAddr) var listeners []net.Listener
listenAddr4 := net.JoinHostPort("127.0.0.1", rpc.rpcport)
listener4, err := net.Listen("tcp4", listenAddr4)
if err != nil { if err != nil {
log.Errorf("[RPCS] Couldn't create listener: %v", err) log.Errorf("[RPCS] Couldn't create listener: %v", err)
return nil, 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 return &rpc, err
} }

View file

@ -40,7 +40,7 @@ type broadcastMsg struct {
// bitcoin peers. // bitcoin peers.
type server struct { type server struct {
nonce uint64 nonce uint64
listener net.Listener listeners []net.Listener
btcnet btcwire.BitcoinNet btcnet btcwire.BitcoinNet
started bool started bool
shutdown 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 // listenHandler is the main listener which accepts incoming connections for the
// server. It must be run as a goroutine. // server. It must be run as a goroutine.
func (s *server) listenHandler() { func (s *server) listenHandler(listener net.Listener) {
log.Infof("[SRVR] Server listening on %s", s.listener.Addr()) log.Infof("[SRVR] Server listening on %s", listener.Addr())
for !s.shutdown { for !s.shutdown {
conn, err := s.listener.Accept() conn, err := listener.Accept()
if err != nil { if err != nil {
// Only log the error if we're not forcibly shutting down. // Only log the error if we're not forcibly shutting down.
if !s.shutdown { if !s.shutdown {
@ -176,14 +176,14 @@ func (s *server) listenHandler() {
s.AddPeer(newPeer(s, conn, true, false)) s.AddPeer(newPeer(s, conn, true, false))
} }
s.wg.Done() 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 // 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 to and from the server, banning peers, and broadcasting messages to
// peers. It must be run a a goroutine. // peers. It must be run a a goroutine.
func (s *server) peerHandler() { func (s *server) peerHandler() {
log.Tracef("[SRVR] Starting peer handler for %s", s.listener.Addr()) log.Tracef("[SRVR] Starting peer handler")
peers := list.New() peers := list.New()
bannedPeers := make(map[string]time.Time) bannedPeers := make(map[string]time.Time)
@ -218,7 +218,7 @@ func (s *server) peerHandler() {
} }
} }
s.wg.Done() 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. // 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") log.Trace("[SRVR] Starting server")
go s.listenHandler() for _, listener := range s.listeners {
go s.listenHandler(listener)
s.wg.Add(1)
}
go s.peerHandler() go s.peerHandler()
s.wg.Add(2) s.wg.Add(1)
s.addrManager.Start() s.addrManager.Start()
s.blockManager.Start() s.blockManager.Start()
if !cfg.DisableRpc { if !cfg.DisableRpc {
@ -305,15 +308,17 @@ func (s *server) Stop() error {
log.Warnf("[SRVR] Server shutting down") log.Warnf("[SRVR] Server shutting down")
s.shutdown = true s.shutdown = true
s.quit <- true close(s.quit)
if !cfg.DisableRpc { if !cfg.DisableRpc {
s.rpcServer.Stop() s.rpcServer.Stop()
} }
s.addrManager.Stop() s.addrManager.Stop()
s.blockManager.Stop() s.blockManager.Stop()
err := s.listener.Close() for _, listener := range s.listeners {
if err != nil { err := listener.Close()
return err if err != nil {
return err
}
} }
return nil return nil
} }
@ -374,14 +379,24 @@ func newServer(addr string, db btcdb.Db, btcnet btcwire.BitcoinNet) (*server, er
return nil, err return nil, err
} }
listener, err := net.Listen("tcp", addr) // IPv4 listener.
var listeners []net.Listener
listener4, err := net.Listen("tcp4", addr)
if err != nil { if err != nil {
return nil, err 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{ s := server{
nonce: nonce, nonce: nonce,
listener: listener, listeners: listeners,
btcnet: btcnet, btcnet: btcnet,
addrManager: NewAddrManager(), addrManager: NewAddrManager(),
newPeers: make(chan *peer, cfg.MaxPeers), newPeers: make(chan *peer, cfg.MaxPeers),