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,
// 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
}

View file

@ -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),