3
0
mirror of https://github.com/ergochat/ergo.git synced 2025-11-13 20:47:24 +01:00

Merge pull request #2299 from ergochat/shivaram_ping.1

configurable idle timeouts
This commit is contained in:
Shivaram Lingamneni 2025-11-09 21:49:39 -05:00 committed by GitHub
commit 68faf82787
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 68 additions and 17 deletions

View File

@ -180,6 +180,17 @@ server:
# if this is true, the motd is escaped using formatting codes like $c, $b, and $i
motd-formatting: true
# idle timeouts for inactive clients
idle-timeouts:
# give the client this long to complete connection registration (i.e. the initial
# IRC handshake, including capability negotiation and SASL)
registration: 60s
# if the client hasn't sent anything for this long, send them a PING
ping: 1m30s
# if the client hasn't sent anything for this long (including the PONG to the
# above PING), disconnect them
disconnect: 2m30s
# relaying using the RELAYMSG command
relaymsg:
# is relaymsg enabled at all?

View File

@ -53,18 +53,16 @@ const (
pushQueueLengthPerClient = 16
)
var (
// idle timeouts for client connections, set from the config
RegisterTimeout, PingTimeout, DisconnectTimeout time.Duration
)
const (
// RegisterTimeout is how long clients have to register before we disconnect them
RegisterTimeout = time.Minute
// DefaultIdleTimeout is how long without traffic before we send the client a PING
DefaultIdleTimeout = time.Minute + 30*time.Second
// For Tor clients, we send a PING at least every 30 seconds, as a workaround for this bug
// (single-onion circuits will close unless the client sends data once every 60 seconds):
// https://bugs.torproject.org/29665
TorIdleTimeout = time.Second * 30
// This is how long a client gets without sending any message, including the PONG to our
// PING, before we disconnect them:
DefaultTotalTimeout = 2*time.Minute + 30*time.Second
TorPingTimeout = time.Second * 30
// round off the ping interval by this much, see below:
PingCoalesceThreshold = time.Second
@ -865,19 +863,19 @@ func (client *Client) updateIdleTimer(session *Session, now time.Time) {
session.pingSent = false
if session.idleTimer == nil {
pingTimeout := DefaultIdleTimeout
if session.isTor {
pingTimeout = TorIdleTimeout
pingTimeout := PingTimeout
if session.isTor && TorPingTimeout < pingTimeout {
pingTimeout = TorPingTimeout
}
session.idleTimer = time.AfterFunc(pingTimeout, session.handleIdleTimeout)
}
}
func (session *Session) handleIdleTimeout() {
totalTimeout := DefaultTotalTimeout
pingTimeout := DefaultIdleTimeout
if session.isTor {
pingTimeout = TorIdleTimeout
totalTimeout := DisconnectTimeout
pingTimeout := PingTimeout
if session.isTor && TorPingTimeout < pingTimeout {
pingTimeout = TorPingTimeout
}
session.client.stateMutex.Lock()

View File

@ -45,6 +45,10 @@ import (
"github.com/ergochat/ergo/irc/webpush"
)
const (
defaultProxyDeadline = time.Minute
)
// here's how this works: exported (capitalized) members of the config structs
// are defined in the YAML file and deserialized directly from there. They may
// be postprocessed and overwritten by LoadConfig. Unexported (lowercase) members
@ -577,7 +581,12 @@ type Config struct {
MOTD string
motdLines []string
MOTDFormatting bool `yaml:"motd-formatting"`
Relaymsg struct {
IdleTimeouts struct {
Registration time.Duration
Ping time.Duration
Disconnect time.Duration
} `yaml:"idle-timeouts"`
Relaymsg struct {
Enabled bool
Separators string
AvailableToChanops bool `yaml:"available-to-chanops"`
@ -987,7 +996,7 @@ func (conf *Config) prepareListeners() (err error) {
conf.Server.trueListeners = make(map[string]utils.ListenerConfig)
for addr, block := range conf.Server.Listeners {
var lconf utils.ListenerConfig
lconf.ProxyDeadline = RegisterTimeout
lconf.ProxyDeadline = defaultProxyDeadline
lconf.Tor = block.Tor
lconf.STSOnly = block.STSOnly
if lconf.STSOnly && !conf.Server.STS.Enabled {
@ -1237,6 +1246,23 @@ func LoadConfig(filename string) (config *Config, err error) {
}
}
if config.Server.IdleTimeouts.Registration <= 0 {
config.Server.IdleTimeouts.Registration = time.Minute
}
if config.Server.IdleTimeouts.Ping <= 0 {
config.Server.IdleTimeouts.Ping = time.Minute + 30*time.Second
}
if config.Server.IdleTimeouts.Disconnect <= 0 {
config.Server.IdleTimeouts.Disconnect = 2*time.Minute + 30*time.Second
}
if !(config.Server.IdleTimeouts.Ping < config.Server.IdleTimeouts.Disconnect) {
return nil, fmt.Errorf(
"ping timeout %v must be strictly less than disconnect timeout %v, to give the client time to respond",
config.Server.IdleTimeouts.Ping, config.Server.IdleTimeouts.Disconnect,
)
}
if config.Server.CoerceIdent != "" {
if config.Server.CheckIdent {
return nil, errors.New("Can't configure both check-ident and coerce-ident")

View File

@ -690,6 +690,9 @@ func (server *Server) applyConfig(config *Config) (err error) {
globalCasemappingSetting = config.Server.Casemapping
globalUtf8EnforcementSetting = config.Server.EnforceUtf8
MaxLineLen = config.Server.MaxLineLen
RegisterTimeout = config.Server.IdleTimeouts.Registration
PingTimeout = config.Server.IdleTimeouts.Ping
DisconnectTimeout = config.Server.IdleTimeouts.Disconnect
} else {
// enforce configs that can't be changed after launch:
if server.name != config.Server.Name {
@ -715,6 +718,8 @@ func (server *Server) applyConfig(config *Config) (err error) {
return fmt.Errorf("Cannot enable MySQL after launching the server, rehash aborted")
} else if oldConfig.Server.MaxLineLen != config.Server.MaxLineLen {
return fmt.Errorf("Cannot change max-line-len after launching the server, rehash aborted")
} else if oldConfig.Server.IdleTimeouts != config.Server.IdleTimeouts {
return fmt.Errorf("Cannot change idle-timeouts after launching the server, rehash aborted")
}
}

View File

@ -154,6 +154,17 @@ server:
# if this is true, the motd is escaped using formatting codes like $c, $b, and $i
motd-formatting: true
# idle timeouts for inactive clients
idle-timeouts:
# give the client this long to complete connection registration (i.e. the initial
# IRC handshake, including capability negotiation and SASL)
registration: 60s
# if the client hasn't sent anything for this long, send them a PING
ping: 1m30s
# if the client hasn't sent anything for this long (including the PONG to the
# above PING), disconnect them
disconnect: 2m30s
# relaying using the RELAYMSG command
relaymsg:
# is relaymsg enabled at all?