hid: figured out how to port timeouts

This commit is contained in:
Přemysl Eric Janouch 2018-08-01 17:49:27 +02:00
parent 3610f98d67
commit cbdbfc3d64
1 changed files with 64 additions and 20 deletions

View File

@ -761,7 +761,7 @@ var (
config simpleConfig // server configuration config simpleConfig // server configuration
serverName string // our server name serverName string // our server name
pingInterval uint // ping interval in seconds pingInterval time.Duration // ping interval
maxConnections int // max connections allowed or 0 maxConnections int // max connections allowed or 0
motd []string // MOTD (none if empty) motd []string // MOTD (none if empty)
operators = make(map[string]bool) // TLS cert. fingerprints for IRCops operators = make(map[string]bool) // TLS cert. fingerprints for IRCops
@ -773,7 +773,7 @@ var (
prepared = make(chan preparedEvent) prepared = make(chan preparedEvent)
reads = make(chan readEvent) reads = make(chan readEvent)
writes = make(chan writeEvent) writes = make(chan writeEvent)
timeouts = make(chan *client) timers = make(chan func())
tlsConf *tls.Config tlsConf *tls.Config
clients = make(map[*client]bool) clients = make(map[*client]bool)
@ -962,12 +962,7 @@ func (c *client) kill(reason string) {
_ = c.transport.Close() _ = c.transport.Close()
} }
// Clean up the goroutine, although a spurious event may still be sent. c.cancelTimers()
// TODO: Other timers if needed.
if c.killTimer != nil {
c.killTimer.Stop()
}
delete(clients, c) delete(clients, c)
} }
@ -994,9 +989,7 @@ func (c *client) closeLink(reason string) {
c.closing = true c.closing = true
c.unregister(reason) c.unregister(reason)
c.killTimer = time.AfterFunc(3*time.Second, func() { c.setKillTimer()
timeouts <- c
})
} }
func (c *client) inMaskList(masks []string) bool { func (c *client) inMaskList(masks []string) bool {
@ -1025,7 +1018,57 @@ func (c *client) getTLSCertFingerprint() string {
// --- Timers ------------------------------------------------------------------ // --- Timers ------------------------------------------------------------------
// TODO // Free the resources of timers that haven't fired yet and for timers that are
// in between firing and being collected by the event loop, mark that the event
// should not be acted upon.
func (c *client) cancelTimers() {
for _, timer := range []**time.Timer{
&c.killTimer, &c.timeoutTimer, &c.pingTimer,
} {
if *timer != nil {
(*timer).Stop()
*timer = nil
}
}
}
// Arrange for a function to be called later from the main goroutine.
func (c *client) setTimer(timer **time.Timer, delay time.Duration, cb func()) {
c.cancelTimers()
var identityCapture *time.Timer
identityCapture = time.AfterFunc(delay, func() {
timers <- func() {
// The timer might have been cancelled or even replaced.
// When the client is killed, this will be nil.
if *timer == identityCapture {
cb()
}
}
})
*timer = identityCapture
}
func (c *client) setKillTimer() {
c.setTimer(&c.killTimer, pingInterval, func() {
c.kill("Timeout")
})
}
func (c *client) setTimeoutTimer() {
c.setTimer(&c.timeoutTimer, pingInterval, func() {
c.closeLink(fmt.Sprintf("Ping timeout: >%d seconds",
pingInterval/time.Second))
})
}
func (c *client) setPingTimer() {
c.setTimer(&c.pingTimer, pingInterval, func() {
c.sendf("PING :%s", serverName)
c.setTimeoutTimer()
})
}
// --- IRC command handling ---------------------------------------------------- // --- IRC command handling ----------------------------------------------------
@ -1451,7 +1494,7 @@ func ircHandlePONG(msg *message, c *client) {
} }
// Set a new timer to send another PING // Set a new timer to send another PING
// TODO c.setPingTimer()
} }
func ircHandleQUIT(msg *message, c *client) { func ircHandleQUIT(msg *message, c *client) {
@ -2817,6 +2860,7 @@ func (c *client) onPrepared(host string, isTLS bool) {
// If we tried to send any data before now, we would need to flushSendQ. // If we tried to send any data before now, we would need to flushSendQ.
go read(c) go read(c)
c.reading = true c.reading = true
c.setPingTimer()
} }
// Handle the results from trying to read from the client connection. // Handle the results from trying to read from the client connection.
@ -2996,6 +3040,9 @@ func processOneEvent() {
case <-quitTimer: case <-quitTimer:
forceQuit("timeout") forceQuit("timeout")
case callback := <-timers:
callback()
case conn := <-conns: case conn := <-conns:
if maxConnections > 0 && len(clients) >= maxConnections { if maxConnections > 0 && len(clients) >= maxConnections {
log.Println("connection limit reached, refusing connection") log.Println("connection limit reached, refusing connection")
@ -3026,6 +3073,9 @@ func processOneEvent() {
clients[c] = true clients[c] = true
go prepare(c) go prepare(c)
// The TLS autodetection in prepare needs to have a timeout.
c.setKillTimer()
case ev := <-prepared: case ev := <-prepared:
log.Println("client is ready:", ev.host) log.Println("client is ready:", ev.host)
if _, ok := clients[ev.client]; ok { if _, ok := clients[ev.client]; ok {
@ -3043,12 +3093,6 @@ func processOneEvent() {
if _, ok := clients[ev.client]; ok { if _, ok := clients[ev.client]; ok {
ev.client.onWrite(ev.written, ev.err) ev.client.onWrite(ev.written, ev.err)
} }
case c := <-timeouts:
if _, ok := clients[c]; ok {
log.Println("client timeouted")
c.kill("TODO")
}
} }
} }
@ -3147,7 +3191,7 @@ func ircParseConfig() error {
} else if u < 1 { } else if u < 1 {
return "the value is out of range" return "the value is out of range"
} else { } else {
pingInterval = uint(u) pingInterval = time.Second * time.Duration(u)
} }
return "" return ""
}) })