diff --git a/controller/config.go b/controller/config.go index 3ca94d7c..1d7b5b9c 100644 --- a/controller/config.go +++ b/controller/config.go @@ -20,9 +20,10 @@ const ( ProtectedMode = "protected-mode" MaxMemory = "maxmemory" AutoGC = "autogc" + KeepAlive = "keepalive" ) -var validProperties = []string{RequirePass, LeaderAuth, ProtectedMode, MaxMemory, AutoGC} +var validProperties = []string{RequirePass, LeaderAuth, ProtectedMode, MaxMemory, AutoGC, KeepAlive} // Config is a tile38 config type Config struct { @@ -44,6 +45,8 @@ type Config struct { MaxMemory int `json:"-"` AutoGCP string `json:"autogc,omitempty"` AutoGC uint64 `json:"-"` + KeepAliveP string `json:"keepalive,omitempty"` + KeepAlive int `json:"-"` } func (c *Controller) loadConfig() error { @@ -74,6 +77,9 @@ func (c *Controller) loadConfig() error { if err := c.setConfigProperty(AutoGC, c.config.AutoGCP, true); err != nil { return err } + if err := c.setConfigProperty(KeepAlive, c.config.KeepAliveP, true); err != nil { + return err + } return nil } @@ -161,7 +167,19 @@ func (c *Controller) setConfigProperty(name, value string, fromLoad bool) error default: invalid = true } + case KeepAlive: + if value == "" { + c.config.KeepAlive = 300 + } else { + keepalive, err := strconv.ParseUint(value, 10, 64) + if err != nil { + invalid = true + } else { + c.config.KeepAlive = int(keepalive) + } + } } + if invalid { return fmt.Errorf("Invalid argument '%s' for CONFIG SET '%s'", value, name) } @@ -192,6 +210,8 @@ func (c *Controller) getConfigProperty(name string) string { return c.config.ProtectedMode case MaxMemory: return formatMemSize(c.config.MaxMemory) + case KeepAlive: + return strconv.FormatUint(uint64(c.config.KeepAlive), 10) } } @@ -216,6 +236,7 @@ func (c *Controller) writeConfig(writeProperties bool) error { c.config.ProtectedModeP = c.config.ProtectedMode c.config.MaxMemoryP = formatMemSize(c.config.MaxMemory) c.config.AutoGCP = strconv.FormatUint(c.config.AutoGC, 10) + c.config.KeepAliveP = strconv.FormatUint(uint64(c.config.KeepAlive), 10) } var data []byte data, err = json.MarshalIndent(c.config, "", "\t") diff --git a/controller/controller.go b/controller/controller.go index 50074d90..eb1ce533 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -227,8 +227,17 @@ func ListenAndServeEx(host string, port int, dir string, ln *net.Listener, http return is } var clientId uint64 + opened := func(conn *server.Conn) { c.mu.Lock() + if c.config.KeepAlive > 0 { + err := conn.SetKeepAlive( + time.Duration(c.config.KeepAlive) * time.Second) + if err != nil { + log.Warnf("could not set keepalive for connection: %v", + conn.RemoteAddr().String()) + } + } clientId++ c.conns[conn] = &clientConn{ id: clientId, diff --git a/controller/server/server.go b/controller/server/server.go index e031304f..fff1bf6b 100644 --- a/controller/server/server.go +++ b/controller/server/server.go @@ -45,6 +45,16 @@ type Conn struct { Authenticated bool } +func (conn Conn) SetKeepAlive(period time.Duration) error { + if tcp, ok := conn.Conn.(*net.TCPConn); ok { + if err := tcp.SetKeepAlive(true); err != nil { + return err + } + return tcp.SetKeepAlivePeriod(period) + } + return nil +} + var errCloseHTTP = errors.New("close http") // ListenAndServe starts a tile38 server at the specified address.