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.
This commit is contained in:
Matheus Degiovani 2022-11-21 16:54:43 -03:00 committed by Dave Collins
parent e9b1b5805a
commit fc017ce3bb
3 changed files with 72 additions and 3 deletions

View File

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

56
ipc.go
View File

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

View File

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