btcd/btcd.go
Owain G. Ainsworth 6116a6cb02 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
2013-11-14 01:15:47 +00:00

133 lines
3.2 KiB
Go

// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package main
import (
"net"
"net/http"
_ "net/http/pprof"
"os"
"runtime"
"runtime/pprof"
)
var (
cfg *config
shutdownChannel = make(chan bool)
)
// btcdMain is the real main function for btcd. It is necessary to work around
// the fact that deferred functions do not run when os.Exit() is called.
func btcdMain() error {
// Initialize logging and setup deferred flushing to ensure all
// outstanding messages are written on shutdown.
loggers := setLogLevel(defaultLogLevel)
defer func() {
for _, logger := range loggers {
logger.Flush()
}
}()
// Load configuration and parse command line.
tcfg, _, err := loadConfig()
if err != nil {
return err
}
cfg = tcfg
// Change the logging level if needed.
if cfg.DebugLevel != defaultLogLevel {
loggers = setLogLevel(cfg.DebugLevel)
}
// Show version at startup.
log.Infof("Version %s", version())
// Enable http profiling server if requested.
if cfg.Profile != "" {
go func() {
listenAddr := net.JoinHostPort("", cfg.Profile)
log.Infof("Profile server listening on %s", listenAddr)
profileRedirect := http.RedirectHandler("/debug/pprof",
http.StatusSeeOther)
http.Handle("/", profileRedirect)
log.Errorf("%v", http.ListenAndServe(listenAddr, nil))
}()
}
// Write cpu profile if requested.
if cfg.CpuProfile != "" {
f, err := os.Create(cfg.CpuProfile)
if err != nil {
log.Errorf("Unable to create cpu profile: %v", err)
return err
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
// Perform upgrades to btcd as new versions require it.
if err := doUpgrades(); err != nil {
log.Errorf("%v", err)
return err
}
// Load the block database.
db, err := loadBlockDB()
if err != nil {
log.Errorf("%v", err)
return err
}
defer db.Close()
// Ensure the database is sync'd and closed on Ctrl+C.
addInterruptHandler(func() {
log.Infof("Gracefully shutting down the database...")
db.RollbackClose()
})
// Create server and start it.
server, err := newServer(cfg.Listeners, db, activeNetParams.btcnet)
if err != nil {
// 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()
// Monitor for graceful server shutdown and signal the main goroutine
// when done. This is done in a separate goroutine rather than waiting
// directly so the main goroutine can be signaled for shutdown by either
// a graceful shutdown or from the main interrupt handler. This is
// necessary since the main goroutine must be kept running long enough
// for the interrupt handler goroutine to finish.
go func() {
server.WaitForShutdown()
shutdownChannel <- true
}()
// Wait for shutdown signal from either a graceful server stop or from
// the interrupt handler.
<-shutdownChannel
log.Info("Shutdown complete")
return nil
}
func main() {
// Use all processor cores.
runtime.GOMAXPROCS(runtime.NumCPU())
// Up some limits.
if err := setLimits(); err != nil {
os.Exit(1)
}
// Work around defer not working after os.Exit()
if err := btcdMain(); err != nil {
os.Exit(1)
}
}