Allow updating Listen during runtime

This commit is contained in:
Neil Alexander 2018-12-30 15:21:09 +00:00
parent f96747181d
commit cb4495902b
No known key found for this signature in database
GPG Key ID: A02A2019A2BB0944
3 changed files with 62 additions and 15 deletions

View File

@ -109,13 +109,14 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) {
components := []chan chan error{ components := []chan chan error{
c.admin.reconfigure, c.admin.reconfigure,
c.searches.reconfigure, //c.searches.reconfigure,
c.dht.reconfigure, //c.dht.reconfigure,
c.sessions.reconfigure, //c.sessions.reconfigure,
//c.peers.reconfigure,
//c.router.reconfigure,
//c.switchTable.reconfigure,
c.tcp.reconfigure,
c.multicast.reconfigure, c.multicast.reconfigure,
c.peers.reconfigure,
c.router.reconfigure,
c.switchTable.reconfigure,
} }
for _, component := range components { for _, component := range components {

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"net" "net"
"sync"
"time" "time"
"golang.org/x/net/ipv6" "golang.org/x/net/ipv6"
@ -14,6 +15,8 @@ type multicast struct {
reconfigure chan chan error reconfigure chan chan error
sock *ipv6.PacketConn sock *ipv6.PacketConn
groupAddr string groupAddr string
myAddr *net.TCPAddr
myAddrMutex sync.RWMutex
} }
func (m *multicast) init(core *Core) { func (m *multicast) init(core *Core) {
@ -23,6 +26,9 @@ func (m *multicast) init(core *Core) {
for { for {
select { select {
case e := <-m.reconfigure: case e := <-m.reconfigure:
m.myAddrMutex.Lock()
m.myAddr = m.core.tcp.getAddr()
m.myAddrMutex.Unlock()
e <- nil e <- nil
} }
} }
@ -95,13 +101,14 @@ func (m *multicast) interfaces() []net.Interface {
} }
func (m *multicast) announce() { func (m *multicast) announce() {
var anAddr net.TCPAddr
m.myAddrMutex.Lock()
m.myAddr = m.core.tcp.getAddr()
m.myAddrMutex.Unlock()
groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr) groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr)
if err != nil { if err != nil {
panic(err) panic(err)
} }
var anAddr net.TCPAddr
myAddr := m.core.tcp.getAddr()
anAddr.Port = myAddr.Port
destAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr) destAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr)
if err != nil { if err != nil {
panic(err) panic(err)
@ -113,6 +120,9 @@ func (m *multicast) announce() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
m.myAddrMutex.RLock()
anAddr.Port = m.myAddr.Port
m.myAddrMutex.RUnlock()
for _, addr := range addrs { for _, addr := range addrs {
addrIP, _, _ := net.ParseCIDR(addr.String()) addrIP, _, _ := net.ParseCIDR(addr.String())
if addrIP.To4() != nil { if addrIP.To4() != nil {

View File

@ -38,7 +38,9 @@ const tcp_ping_interval = (default_tcp_timeout * 2 / 3)
// The TCP listener and information about active TCP connections, to avoid duplication. // The TCP listener and information about active TCP connections, to avoid duplication.
type tcpInterface struct { type tcpInterface struct {
core *Core core *Core
reconfigure chan chan error
serv net.Listener serv net.Listener
serv_stop chan bool
tcp_timeout time.Duration tcp_timeout time.Duration
tcp_addr string tcp_addr string
mutex sync.Mutex // Protecting the below mutex sync.Mutex // Protecting the below
@ -83,10 +85,37 @@ func (iface *tcpInterface) connectSOCKS(socksaddr, peeraddr string) {
// Initializes the struct. // Initializes the struct.
func (iface *tcpInterface) init(core *Core) (err error) { func (iface *tcpInterface) init(core *Core) (err error) {
iface.core = core iface.core = core
iface.serv_stop = make(chan bool, 1)
iface.reconfigure = make(chan chan error, 1)
go func() {
for {
select {
case e := <-iface.reconfigure:
iface.core.configMutex.RLock()
updated := iface.core.config.Listen != iface.core.configOld.Listen
iface.core.configMutex.RUnlock()
if updated {
iface.serv_stop <- true
iface.serv.Close()
e <- iface.listen()
} else {
e <- nil
}
}
}
}()
return iface.listen()
}
func (iface *tcpInterface) listen() error {
var err error
iface.core.configMutex.RLock() iface.core.configMutex.RLock()
iface.tcp_addr = iface.core.config.Listen iface.tcp_addr = iface.core.config.Listen
iface.tcp_timeout = time.Duration(iface.core.config.ReadTimeout) * time.Millisecond iface.tcp_timeout = time.Duration(iface.core.config.ReadTimeout) * time.Millisecond
iface.core.configMutex.RUnlock() iface.core.configMutex.RUnlock()
if iface.tcp_timeout >= 0 && iface.tcp_timeout < default_tcp_timeout { if iface.tcp_timeout >= 0 && iface.tcp_timeout < default_tcp_timeout {
iface.tcp_timeout = default_tcp_timeout iface.tcp_timeout = default_tcp_timeout
} }
@ -96,6 +125,7 @@ func (iface *tcpInterface) init(core *Core) (err error) {
iface.calls = make(map[string]struct{}) iface.calls = make(map[string]struct{})
iface.conns = make(map[tcpInfo](chan struct{})) iface.conns = make(map[tcpInfo](chan struct{}))
go iface.listener() go iface.listener()
return nil
} }
return err return err
@ -107,10 +137,16 @@ func (iface *tcpInterface) listener() {
iface.core.log.Println("Listening for TCP on:", iface.serv.Addr().String()) iface.core.log.Println("Listening for TCP on:", iface.serv.Addr().String())
for { for {
sock, err := iface.serv.Accept() sock, err := iface.serv.Accept()
if err != nil { select {
panic(err) case <-iface.serv_stop:
iface.core.log.Println("Stopping listener")
return
default:
if err != nil {
panic(err)
}
go iface.handler(sock, true)
} }
go iface.handler(sock, true)
} }
} }
@ -363,12 +399,12 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) {
themAddr := address.AddrForNodeID(themNodeID) themAddr := address.AddrForNodeID(themNodeID)
themAddrString := net.IP(themAddr[:]).String() themAddrString := net.IP(themAddr[:]).String()
themString := fmt.Sprintf("%s@%s", themAddrString, them) themString := fmt.Sprintf("%s@%s", themAddrString, them)
iface.core.log.Println("Connected:", themString, "source", us) iface.core.log.Printf("Connected: %s, source: %s", themString, us)
err = iface.reader(sock, in) // In this goroutine, because of defers err = iface.reader(sock, in) // In this goroutine, because of defers
if err == nil { if err == nil {
iface.core.log.Println("Disconnected:", themString, "source", us) iface.core.log.Printf("Disconnected: %s, source: %s", themString, us)
} else { } else {
iface.core.log.Println("Disconnected:", themString, "source", us, "with error:", err) iface.core.log.Printf("Disconnected: %s, source: %s, error: %s", themString, us, err)
} }
return return
} }