Support --listen.
This allows the provision of address/port pairs to be listened on instead of just providing the port. e.g.: btcd --listen 1.2.3.4:4321 --listen 127.0.0.01 --listen [::1]:5432 When --proxy and --connect are used, we disable listening *unless* any --listen arguments have been provided, when we will listen on those addresses as requested. Initial code by davec, integration by myself. Closes #33 allow listens to fail, but warn. error if all failed fmt
This commit is contained in:
parent
3108b94401
commit
6116a6cb02
4 changed files with 115 additions and 44 deletions
7
btcd.go
7
btcd.go
|
@ -89,10 +89,11 @@ func btcdMain() error {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create server and start it.
|
// Create server and start it.
|
||||||
listenAddr := net.JoinHostPort("", cfg.Port)
|
server, err := newServer(cfg.Listeners, db, activeNetParams.btcnet)
|
||||||
server, err := newServer(listenAddr, db, activeNetParams.btcnet)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Unable to start server on %v: %v", listenAddr, err)
|
// TODO(oga) this logging could do with some beautifying.
|
||||||
|
log.Errorf("Unable to start server on %v: %v",
|
||||||
|
cfg.Listeners, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
server.Start()
|
server.Start()
|
||||||
|
|
81
config.go
81
config.go
|
@ -34,6 +34,7 @@ var (
|
||||||
btcdHomeDir = btcutil.AppDataDir("btcd", false)
|
btcdHomeDir = btcutil.AppDataDir("btcd", false)
|
||||||
defaultConfigFile = filepath.Join(btcdHomeDir, defaultConfigFilename)
|
defaultConfigFile = filepath.Join(btcdHomeDir, defaultConfigFilename)
|
||||||
defaultDataDir = filepath.Join(btcdHomeDir, defaultDataDirname)
|
defaultDataDir = filepath.Join(btcdHomeDir, defaultDataDirname)
|
||||||
|
defaultListener = net.JoinHostPort("", netParams(defaultBtcnet).listenPort)
|
||||||
knownDbTypes = btcdb.SupportedDBs()
|
knownDbTypes = btcdb.SupportedDBs()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ type config struct {
|
||||||
AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"`
|
AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"`
|
||||||
ConnectPeers []string `long:"connect" description:"Connect only to the specified peers at startup"`
|
ConnectPeers []string `long:"connect" description:"Connect only to the specified peers at startup"`
|
||||||
DisableListen bool `long:"nolisten" description:"Disable listening for incoming connections -- NOTE: Listening is automatically disabled if the --connect option is used or if the --proxy option is used without the --tor option"`
|
DisableListen bool `long:"nolisten" description:"Disable listening for incoming connections -- NOTE: Listening is automatically disabled if the --connect option is used or if the --proxy option is used without the --tor option"`
|
||||||
Port string `short:"p" long:"port" description:"Listen for connections on this port (default: 8333, testnet: 18333)"`
|
Listeners []string `long:"listen" description:"Listen for connections on this interface/port (default all interfaces port: 8333, testnet: 18333)"`
|
||||||
MaxPeers int `long:"maxpeers" description:"Max number of inbound and outbound peers"`
|
MaxPeers int `long:"maxpeers" description:"Max number of inbound and outbound peers"`
|
||||||
BanDuration time.Duration `long:"banduration" description:"How long to ban misbehaving peers. Valid time units are {s, m, h}. Minimum 1 second"`
|
BanDuration time.Duration `long:"banduration" description:"How long to ban misbehaving peers. Valid time units are {s, m, h}. Minimum 1 second"`
|
||||||
RPCUser string `short:"u" long:"rpcuser" description:"Username for RPC connections"`
|
RPCUser string `short:"u" long:"rpcuser" description:"Username for RPC connections"`
|
||||||
|
@ -112,16 +113,6 @@ func validDbType(dbType string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalizePeerAddress returns addr with the default peer port appended if
|
|
||||||
// there is not already a port specified.
|
|
||||||
func normalizePeerAddress(addr string) string {
|
|
||||||
_, _, err := net.SplitHostPort(addr)
|
|
||||||
if err != nil {
|
|
||||||
return net.JoinHostPort(addr, activeNetParams.peerPort)
|
|
||||||
}
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
// removeDuplicateAddresses returns a new slice with all duplicate entries in
|
// removeDuplicateAddresses returns a new slice with all duplicate entries in
|
||||||
// addrs removed.
|
// addrs removed.
|
||||||
func removeDuplicateAddresses(addrs []string) []string {
|
func removeDuplicateAddresses(addrs []string) []string {
|
||||||
|
@ -136,15 +127,36 @@ func removeDuplicateAddresses(addrs []string) []string {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalizeAndRemoveDuplicateAddresses return a new slice with all the passed
|
// normalizeAddress returns addr with the passed default port appended if
|
||||||
// addresses normalized and duplicates removed.
|
// there is not already a port specified.
|
||||||
func normalizeAndRemoveDuplicateAddresses(addrs []string) []string {
|
func normalizeAddress(addr, defaultPort string) string {
|
||||||
for i, addr := range addrs {
|
_, _, err := net.SplitHostPort(addr)
|
||||||
addrs[i] = normalizePeerAddress(addr)
|
if err != nil {
|
||||||
|
return net.JoinHostPort(addr, defaultPort)
|
||||||
}
|
}
|
||||||
addrs = removeDuplicateAddresses(addrs)
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
return addrs
|
// normalizeAddresses returns a new slice with all the passed peer addresses
|
||||||
|
// normalized with the given default port, and all duplicates removed.
|
||||||
|
func normalizeAddresses(addrs []string, defaultPort string) []string {
|
||||||
|
for i, addr := range addrs {
|
||||||
|
addrs[i] = normalizeAddress(addr, defaultPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
return removeDuplicateAddresses(addrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanListenAddresses returns a new slice with all the passed peer addresses
|
||||||
|
// normalized and duplicates removed.
|
||||||
|
func cleanListenAddresses(addrs []string) []string {
|
||||||
|
return normalizeAddresses(addrs, activeNetParams.listenPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanPeerAddresses returns a new slice with all the passed peer addresses
|
||||||
|
// normalized and duplicates removed.
|
||||||
|
func cleanPeerAddresses(addrs []string) []string {
|
||||||
|
return normalizeAddresses(addrs, activeNetParams.peerPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateConfigWithActiveParams update the passed config with parameters
|
// updateConfigWithActiveParams update the passed config with parameters
|
||||||
|
@ -152,9 +164,10 @@ func normalizeAndRemoveDuplicateAddresses(addrs []string) []string {
|
||||||
// object are the default so options specified by the user on the command line
|
// object are the default so options specified by the user on the command line
|
||||||
// are not overridden.
|
// are not overridden.
|
||||||
func updateConfigWithActiveParams(cfg *config) {
|
func updateConfigWithActiveParams(cfg *config) {
|
||||||
if cfg.Port == netParams(defaultBtcnet).listenPort {
|
// Even though there should only be one default, a duplicate might
|
||||||
cfg.Port = activeNetParams.listenPort
|
// have been specified via the config file or CLI options. So, make
|
||||||
}
|
// sure to update all default entries rather than only the first one
|
||||||
|
// found. Duplicates are removed later.
|
||||||
|
|
||||||
if cfg.RPCPort == netParams(defaultBtcnet).rpcPort {
|
if cfg.RPCPort == netParams(defaultBtcnet).rpcPort {
|
||||||
cfg.RPCPort = activeNetParams.rpcPort
|
cfg.RPCPort = activeNetParams.rpcPort
|
||||||
|
@ -187,7 +200,6 @@ func loadConfig() (*config, []string, error) {
|
||||||
// Default config.
|
// Default config.
|
||||||
cfg := config{
|
cfg := config{
|
||||||
DebugLevel: defaultLogLevel,
|
DebugLevel: defaultLogLevel,
|
||||||
Port: netParams(defaultBtcnet).listenPort,
|
|
||||||
RPCPort: netParams(defaultBtcnet).rpcPort,
|
RPCPort: netParams(defaultBtcnet).rpcPort,
|
||||||
MaxPeers: defaultMaxPeers,
|
MaxPeers: defaultMaxPeers,
|
||||||
BanDuration: defaultBanDuration,
|
BanDuration: defaultBanDuration,
|
||||||
|
@ -329,15 +341,24 @@ func loadConfig() (*config, []string, error) {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// --proxy without --tor means no listening.
|
// --proxy or --connect without --listen disables listening.
|
||||||
if cfg.Proxy != "" && !cfg.UseTor {
|
if (cfg.Proxy != "" || len(cfg.ConnectPeers) > 0) &&
|
||||||
|
len(cfg.Listeners) == 0 {
|
||||||
cfg.DisableListen = true
|
cfg.DisableListen = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect means no seeding or listening.
|
// Connect means no DNS seeding.
|
||||||
if len(cfg.ConnectPeers) > 0 {
|
if len(cfg.ConnectPeers) > 0 {
|
||||||
cfg.DisableDNSSeed = true
|
cfg.DisableDNSSeed = true
|
||||||
cfg.DisableListen = true
|
}
|
||||||
|
|
||||||
|
// Add the default listener if none were specified. The default
|
||||||
|
// listener is all addresses on the listen port for the network
|
||||||
|
// we are to connect to.
|
||||||
|
if len(cfg.Listeners) == 0 {
|
||||||
|
cfg.Listeners = []string{
|
||||||
|
net.JoinHostPort("", activeNetParams.listenPort),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The RPC server is disabled if no username or password is provided.
|
// The RPC server is disabled if no username or password is provided.
|
||||||
|
@ -345,10 +366,14 @@ func loadConfig() (*config, []string, error) {
|
||||||
cfg.DisableRPC = true
|
cfg.DisableRPC = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add default port to all listner addresses if needed and remove
|
||||||
|
// duplicate addresses.
|
||||||
|
cfg.Listeners = cleanListenAddresses(cfg.Listeners)
|
||||||
|
|
||||||
// Add default port to all added peer addresses if needed and remove
|
// Add default port to all added peer addresses if needed and remove
|
||||||
// duplicate addresses.
|
// duplicate addresses.
|
||||||
cfg.AddPeers = normalizeAndRemoveDuplicateAddresses(cfg.AddPeers)
|
cfg.AddPeers = cleanPeerAddresses(cfg.AddPeers)
|
||||||
cfg.ConnectPeers = normalizeAndRemoveDuplicateAddresses(cfg.ConnectPeers)
|
cfg.ConnectPeers = cleanPeerAddresses(cfg.ConnectPeers)
|
||||||
|
|
||||||
return &cfg, remainingArgs, nil
|
return &cfg, remainingArgs, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -503,7 +503,7 @@ func handleAddNode(s *rpcServer, cmd btcjson.Cmd,
|
||||||
walletNotification chan []byte) (interface{}, error) {
|
walletNotification chan []byte) (interface{}, error) {
|
||||||
c := cmd.(*btcjson.AddNodeCmd)
|
c := cmd.(*btcjson.AddNodeCmd)
|
||||||
|
|
||||||
addr := normalizePeerAddress(c.Addr)
|
addr := normalizeAddress(c.Addr, activeNetParams.peerPort)
|
||||||
var err error
|
var err error
|
||||||
switch c.SubCmd {
|
switch c.SubCmd {
|
||||||
case "add":
|
case "add":
|
||||||
|
|
69
server.go
69
server.go
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/conformal/btcdb"
|
"github.com/conformal/btcdb"
|
||||||
"github.com/conformal/btcwire"
|
"github.com/conformal/btcwire"
|
||||||
"net"
|
"net"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
@ -765,30 +766,74 @@ func (s *server) ScheduleShutdown(duration time.Duration) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseListeners(addrs []string) ([]string, []string, error) {
|
||||||
|
ipv4ListenAddrs := make([]string, 0, len(cfg.Listeners)*2)
|
||||||
|
ipv6ListenAddrs := make([]string, 0, len(cfg.Listeners)*2)
|
||||||
|
for _, addr := range cfg.Listeners {
|
||||||
|
host, _, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
// shouldn't happen, should have already been normalized.
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty host or host of * on plan9 is both IPv4 and
|
||||||
|
// IPv6.
|
||||||
|
if host == "" || (host == "*" && runtime.GOOS == "plan9") {
|
||||||
|
ipv4ListenAddrs = append(ipv4ListenAddrs, addr)
|
||||||
|
ipv6ListenAddrs = append(ipv6ListenAddrs, addr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the IP.
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
if ip == nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip.To4() == nil {
|
||||||
|
ipv6ListenAddrs = append(ipv6ListenAddrs, addr)
|
||||||
|
} else {
|
||||||
|
ipv4ListenAddrs = append(ipv4ListenAddrs, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ipv4ListenAddrs, ipv6ListenAddrs, nil
|
||||||
|
}
|
||||||
|
|
||||||
// newServer returns a new btcd server configured to listen on addr for the
|
// newServer returns a new btcd server configured to listen on addr for the
|
||||||
// bitcoin network type specified in btcnet. Use start to begin accepting
|
// bitcoin network type specified in btcnet. Use start to begin accepting
|
||||||
// connections from peers.
|
// connections from peers.
|
||||||
func newServer(addr string, db btcdb.Db, btcnet btcwire.BitcoinNet) (*server, error) {
|
func newServer(listenAddrs []string, db btcdb.Db, btcnet btcwire.BitcoinNet) (*server, error) {
|
||||||
nonce, err := btcwire.RandomUint64()
|
nonce, err := btcwire.RandomUint64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var listeners []net.Listener
|
ipv4ListenAddrs, ipv6ListenAddrs, err := parseListeners(listenAddrs)
|
||||||
|
listeners := make([]net.Listener, 0,
|
||||||
|
len(ipv6ListenAddrs)+len(ipv4ListenAddrs))
|
||||||
if !cfg.DisableListen {
|
if !cfg.DisableListen {
|
||||||
// IPv4 listener.
|
for _, addr := range ipv4ListenAddrs {
|
||||||
listener4, err := net.Listen("tcp4", addr)
|
listener, err := net.Listen("tcp4", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
log.Warnf("SRVR: Can't listen on %s: %v", addr,
|
||||||
|
err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
listeners = append(listeners, listener)
|
||||||
}
|
}
|
||||||
listeners = append(listeners, listener4)
|
|
||||||
|
|
||||||
// IPv6 listener.
|
for _, addr := range ipv6ListenAddrs {
|
||||||
listener6, err := net.Listen("tcp6", addr)
|
listener, err := net.Listen("tcp6", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
log.Warnf("SRVR: Can't listen on %s: %v", addr,
|
||||||
|
err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
listeners = append(listeners, listener)
|
||||||
|
}
|
||||||
|
if len(listeners) == 0 {
|
||||||
|
return nil, errors.New("SRVR: No valid listen address")
|
||||||
}
|
}
|
||||||
listeners = append(listeners, listener6)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s := server{
|
s := server{
|
||||||
|
|
Loading…
Reference in a new issue