From fc017ce3bb3bba23d5a599eb948c1b74ea54b4f5 Mon Sep 17 00:00:00 2001 From: Matheus Degiovani Date: Mon, 21 Nov 2022 16:54:43 -0300 Subject: [PATCH] server: Add bound addresses IPC events This adds a new set of IPC events sent over the TX pipe that report the locally bound addresses of the P2P and RPC interfaces. The main goal for this feature is to enable binding dcrd to a random port (using for example, --listen :0) while enabling a controlling parent process to learn the address that was assigned to dcrd by the OS. The events are only sent when the --boundaddrevents flag is specified. --- config.go | 7 ++++--- ipc.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ server.go | 12 ++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/config.go b/config.go index c5cf8083d2..3928523cfd 100644 --- a/config.go +++ b/config.go @@ -213,9 +213,10 @@ type config struct { DropExistsAddrIndex bool `long:"dropexistsaddrindex" description:"Deletes the exists address index from the database on start up and then exits"` // IPC options. - PipeRx uint `long:"piperx" description:"File descriptor of read end pipe to enable parent -> child process communication"` - PipeTx uint `long:"pipetx" description:"File descriptor of write end pipe to enable parent <- child process communication"` - LifetimeEvents bool `long:"lifetimeevents" description:"Send lifetime notifications over the TX pipe"` + PipeRx uint `long:"piperx" description:"File descriptor of read end pipe to enable parent -> child process communication"` + PipeTx uint `long:"pipetx" description:"File descriptor of write end pipe to enable parent <- child process communication"` + LifetimeEvents bool `long:"lifetimeevents" description:"Send lifetime notifications over the TX pipe"` + BoundAddrEvents bool `long:"boundaddrevents" description:"Send notifications with the locally bound addresses of the P2P and RPC subsystems over the TX pipe"` // Cooked options ready for use. onionlookup func(string) ([]net.IP, error) diff --git a/ipc.go b/ipc.go index f6fb97481a..6415f9bdc3 100644 --- a/ipc.go +++ b/ipc.go @@ -205,3 +205,59 @@ func (s lifetimeEventServer) notifyShutdownEvent(action lifetimeAction) { action: action, } } + +// boundP2PListenAddrEvent are IPC events emitted by dcrd with the bound local +// addresses for the P2P interface. Multiple events of this type may be +// generated. +// +// The type of this event is "p2plistenaddr" and the payload is the UTF-8 +// encoded address. +type boundP2PListenAddrEvent string + +func (e boundP2PListenAddrEvent) Type() string { return "p2plistenaddr" } +func (e boundP2PListenAddrEvent) PayloadSize() uint32 { return uint32(len(e)) } +func (e boundP2PListenAddrEvent) WritePayload(w io.Writer) error { + _, err := w.Write([]byte(e)) + return err +} + +// boundRPCListenAddrEvent are IPC events emitted by dcrd with the bound local +// addresses for the RPC interface. Multiple events of this type may be +// generated. +// +// The type of this event is "rpclistenaddr" and the payload is the UTF-8 +// encoded address. +type boundRPCListenAddrEvent string + +func (e boundRPCListenAddrEvent) Type() string { return "rpclistenaddr" } +func (e boundRPCListenAddrEvent) PayloadSize() uint32 { return uint32(len(e)) } +func (e boundRPCListenAddrEvent) WritePayload(w io.Writer) error { + _, err := w.Write([]byte(e)) + return err +} + +// boundAddrEventServer is a server that can notify parent processes, via the +// IPC mechanism, the local addresses to which specific subsystems are bound +// during initialization. +// +// The empty value is a valid server and will not send any events if its +// notify* methods are called. +type boundAddrEventServer chan<- pipeMessage + +func newBoundAddrEventServer(outChan chan<- pipeMessage) boundAddrEventServer { + return boundAddrEventServer(outChan) +} + +func (s boundAddrEventServer) notifyP2PAddress(addr string) { + if s == nil { + return + } + s <- boundP2PListenAddrEvent(addr) +} + +func (s boundAddrEventServer) notifyRPCAddress(addr string) { + if s == nil { + return + } + s <- boundRPCListenAddrEvent(addr) +} diff --git a/server.go b/server.go index be95b7b5d2..0bf1e4b548 100644 --- a/server.go +++ b/server.go @@ -3277,6 +3277,11 @@ func genCertPair(certFile, keyFile string, altDNSNames []string, tlsCurve ellipt // with the RPC server depending on the configuration settings for listen // addresses and TLS. func setupRPCListeners() ([]net.Listener, error) { + var notifyAddrServer boundAddrEventServer + if cfg.BoundAddrEvents { + notifyAddrServer = newBoundAddrEventServer(outgoingPipeMessages) + } + // Setup TLS if not disabled. listenFunc := net.Listen if !cfg.DisableRPC && !cfg.DisableTLS { @@ -3342,6 +3347,7 @@ func setupRPCListeners() ([]net.Listener, error) { continue } listeners = append(listeners, listener) + notifyAddrServer.notifyRPCAddress(listener.Addr().String()) } return listeners, nil @@ -3833,6 +3839,11 @@ func initListeners(ctx context.Context, params *chaincfg.Params, amgr *addrmgr.A return nil, nil, err } + var notifyAddrServer boundAddrEventServer + if cfg.BoundAddrEvents { + notifyAddrServer = newBoundAddrEventServer(outgoingPipeMessages) + } + listeners := make([]net.Listener, 0, len(netAddrs)) for _, addr := range netAddrs { var listenConfig net.ListenConfig @@ -3842,6 +3853,7 @@ func initListeners(ctx context.Context, params *chaincfg.Params, amgr *addrmgr.A continue } listeners = append(listeners, listener) + notifyAddrServer.notifyP2PAddress(listener.Addr().String()) } var nat *upnpNAT