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.
|
||||
listenAddr := net.JoinHostPort("", cfg.Port)
|
||||
server, err := newServer(listenAddr, db, activeNetParams.btcnet)
|
||||
server, err := newServer(cfg.Listeners, db, activeNetParams.btcnet)
|
||||
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
|
||||
}
|
||||
server.Start()
|
||||
|
|
81
config.go
81
config.go
|
@ -34,6 +34,7 @@ var (
|
|||
btcdHomeDir = btcutil.AppDataDir("btcd", false)
|
||||
defaultConfigFile = filepath.Join(btcdHomeDir, defaultConfigFilename)
|
||||
defaultDataDir = filepath.Join(btcdHomeDir, defaultDataDirname)
|
||||
defaultListener = net.JoinHostPort("", netParams(defaultBtcnet).listenPort)
|
||||
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"`
|
||||
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"`
|
||||
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"`
|
||||
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"`
|
||||
|
@ -112,16 +113,6 @@ func validDbType(dbType string) bool {
|
|||
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
|
||||
// addrs removed.
|
||||
func removeDuplicateAddresses(addrs []string) []string {
|
||||
|
@ -136,15 +127,36 @@ func removeDuplicateAddresses(addrs []string) []string {
|
|||
return result
|
||||
}
|
||||
|
||||
// normalizeAndRemoveDuplicateAddresses return a new slice with all the passed
|
||||
// addresses normalized and duplicates removed.
|
||||
func normalizeAndRemoveDuplicateAddresses(addrs []string) []string {
|
||||
for i, addr := range addrs {
|
||||
addrs[i] = normalizePeerAddress(addr)
|
||||
// normalizeAddress returns addr with the passed default port appended if
|
||||
// there is not already a port specified.
|
||||
func normalizeAddress(addr, defaultPort string) string {
|
||||
_, _, err := net.SplitHostPort(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
|
||||
|
@ -152,9 +164,10 @@ func normalizeAndRemoveDuplicateAddresses(addrs []string) []string {
|
|||
// object are the default so options specified by the user on the command line
|
||||
// are not overridden.
|
||||
func updateConfigWithActiveParams(cfg *config) {
|
||||
if cfg.Port == netParams(defaultBtcnet).listenPort {
|
||||
cfg.Port = activeNetParams.listenPort
|
||||
}
|
||||
// Even though there should only be one default, a duplicate might
|
||||
// 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 {
|
||||
cfg.RPCPort = activeNetParams.rpcPort
|
||||
|
@ -187,7 +200,6 @@ func loadConfig() (*config, []string, error) {
|
|||
// Default config.
|
||||
cfg := config{
|
||||
DebugLevel: defaultLogLevel,
|
||||
Port: netParams(defaultBtcnet).listenPort,
|
||||
RPCPort: netParams(defaultBtcnet).rpcPort,
|
||||
MaxPeers: defaultMaxPeers,
|
||||
BanDuration: defaultBanDuration,
|
||||
|
@ -329,15 +341,24 @@ func loadConfig() (*config, []string, error) {
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
// --proxy without --tor means no listening.
|
||||
if cfg.Proxy != "" && !cfg.UseTor {
|
||||
// --proxy or --connect without --listen disables listening.
|
||||
if (cfg.Proxy != "" || len(cfg.ConnectPeers) > 0) &&
|
||||
len(cfg.Listeners) == 0 {
|
||||
cfg.DisableListen = true
|
||||
}
|
||||
|
||||
// Connect means no seeding or listening.
|
||||
// Connect means no DNS seeding.
|
||||
if len(cfg.ConnectPeers) > 0 {
|
||||
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.
|
||||
|
@ -345,10 +366,14 @@ func loadConfig() (*config, []string, error) {
|
|||
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
|
||||
// duplicate addresses.
|
||||
cfg.AddPeers = normalizeAndRemoveDuplicateAddresses(cfg.AddPeers)
|
||||
cfg.ConnectPeers = normalizeAndRemoveDuplicateAddresses(cfg.ConnectPeers)
|
||||
cfg.AddPeers = cleanPeerAddresses(cfg.AddPeers)
|
||||
cfg.ConnectPeers = cleanPeerAddresses(cfg.ConnectPeers)
|
||||
|
||||
return &cfg, remainingArgs, nil
|
||||
}
|
||||
|
|
|
@ -503,7 +503,7 @@ func handleAddNode(s *rpcServer, cmd btcjson.Cmd,
|
|||
walletNotification chan []byte) (interface{}, error) {
|
||||
c := cmd.(*btcjson.AddNodeCmd)
|
||||
|
||||
addr := normalizePeerAddress(c.Addr)
|
||||
addr := normalizeAddress(c.Addr, activeNetParams.peerPort)
|
||||
var err error
|
||||
switch c.SubCmd {
|
||||
case "add":
|
||||
|
|
69
server.go
69
server.go
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/conformal/btcdb"
|
||||
"github.com/conformal/btcwire"
|
||||
"net"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"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
|
||||
// bitcoin network type specified in btcnet. Use start to begin accepting
|
||||
// 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()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var listeners []net.Listener
|
||||
ipv4ListenAddrs, ipv6ListenAddrs, err := parseListeners(listenAddrs)
|
||||
listeners := make([]net.Listener, 0,
|
||||
len(ipv6ListenAddrs)+len(ipv4ListenAddrs))
|
||||
if !cfg.DisableListen {
|
||||
// IPv4 listener.
|
||||
listener4, err := net.Listen("tcp4", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for _, addr := range ipv4ListenAddrs {
|
||||
listener, err := net.Listen("tcp4", addr)
|
||||
if err != nil {
|
||||
log.Warnf("SRVR: Can't listen on %s: %v", addr,
|
||||
err)
|
||||
continue
|
||||
}
|
||||
listeners = append(listeners, listener)
|
||||
}
|
||||
listeners = append(listeners, listener4)
|
||||
|
||||
// IPv6 listener.
|
||||
listener6, err := net.Listen("tcp6", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for _, addr := range ipv6ListenAddrs {
|
||||
listener, err := net.Listen("tcp6", addr)
|
||||
if err != nil {
|
||||
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{
|
||||
|
|
Loading…
Reference in a new issue