| // Copyright 2015 The etcd Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package transport |
| |
| import ( |
| "crypto/tls" |
| "fmt" |
| "net" |
| "time" |
| ) |
| |
| type keepAliveConn interface { |
| SetKeepAlive(bool) error |
| SetKeepAlivePeriod(d time.Duration) error |
| } |
| |
| // NewKeepAliveListener returns a listener that listens on the given address. |
| // Be careful when wrap around KeepAliveListener with another Listener if TLSInfo is not nil. |
| // Some pkgs (like go/http) might expect Listener to return TLSConn type to start TLS handshake. |
| // http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html |
| func NewKeepAliveListener(l net.Listener, scheme string, tlscfg *tls.Config) (net.Listener, error) { |
| if scheme == "https" { |
| if tlscfg == nil { |
| return nil, fmt.Errorf("cannot listen on TLS for given listener: KeyFile and CertFile are not presented") |
| } |
| return newTLSKeepaliveListener(l, tlscfg), nil |
| } |
| |
| return &keepaliveListener{ |
| Listener: l, |
| }, nil |
| } |
| |
| type keepaliveListener struct{ net.Listener } |
| |
| func (kln *keepaliveListener) Accept() (net.Conn, error) { |
| c, err := kln.Listener.Accept() |
| if err != nil { |
| return nil, err |
| } |
| kac := c.(keepAliveConn) |
| // detection time: tcp_keepalive_time + tcp_keepalive_probes + tcp_keepalive_intvl |
| // default on linux: 30 + 8 * 30 |
| // default on osx: 30 + 8 * 75 |
| kac.SetKeepAlive(true) |
| kac.SetKeepAlivePeriod(30 * time.Second) |
| return c, nil |
| } |
| |
| // A tlsKeepaliveListener implements a network listener (net.Listener) for TLS connections. |
| type tlsKeepaliveListener struct { |
| net.Listener |
| config *tls.Config |
| } |
| |
| // Accept waits for and returns the next incoming TLS connection. |
| // The returned connection c is a *tls.Conn. |
| func (l *tlsKeepaliveListener) Accept() (c net.Conn, err error) { |
| c, err = l.Listener.Accept() |
| if err != nil { |
| return |
| } |
| kac := c.(keepAliveConn) |
| // detection time: tcp_keepalive_time + tcp_keepalive_probes + tcp_keepalive_intvl |
| // default on linux: 30 + 8 * 30 |
| // default on osx: 30 + 8 * 75 |
| kac.SetKeepAlive(true) |
| kac.SetKeepAlivePeriod(30 * time.Second) |
| c = tls.Server(c, l.config) |
| return c, nil |
| } |
| |
| // NewListener creates a Listener which accepts connections from an inner |
| // Listener and wraps each connection with Server. |
| // The configuration config must be non-nil and must have |
| // at least one certificate. |
| func newTLSKeepaliveListener(inner net.Listener, config *tls.Config) net.Listener { |
| l := &tlsKeepaliveListener{} |
| l.Listener = inner |
| l.config = config |
| return l |
| } |