1
// Copyright 2019 The Gitea Authors. All rights reserved.
2
// SPDX-License-Identifier: MIT
4
// This code is highly inspired by endless go
18
"code.gitea.io/gitea/modules/log"
19
"code.gitea.io/gitea/modules/proxyprotocol"
20
"code.gitea.io/gitea/modules/setting"
23
// GetListener returns a net listener
24
// This determines the implementation of net.Listener which the server will use,
25
// so that downstreams could provide their own Listener, such as with a hidden service or a p2p network
26
var GetListener = DefaultGetListener
28
// ServeFunction represents a listen.Accept loop
29
type ServeFunction = func(net.Listener) error
31
// Server represents our graceful server
39
BeforeBegin func(network, address string)
41
PerWriteTimeout time.Duration
42
PerWritePerKbTimeout time.Duration
45
// NewServer creates a server on network at provided address
46
func NewServer(network, address, name string) *Server {
47
if GetManager().IsChild() {
48
log.Info("Restarting new %s server: %s:%s on PID: %d", name, network, address, os.Getpid())
50
log.Info("Starting new %s server: %s:%s on PID: %d", name, network, address, os.Getpid())
55
lock: &sync.RWMutex{},
58
PerWriteTimeout: setting.PerWriteTimeout,
59
PerWritePerKbTimeout: setting.PerWritePerKbTimeout,
62
srv.BeforeBegin = func(network, addr string) {
63
log.Debug("Starting server on %s:%s (PID: %d)", network, addr, syscall.Getpid())
69
// ListenAndServe listens on the provided network address and then calls Serve
70
// to handle requests on incoming connections.
71
func (srv *Server) ListenAndServe(serve ServeFunction, useProxyProtocol bool) error {
72
go srv.awaitShutdown()
74
listener, err := GetListener(srv.network, srv.address)
76
log.Error("Unable to GetListener: %v", err)
80
// we need to wrap the listener to take account of our lifecycle
81
listener = newWrappedListener(listener, srv)
83
// Now we need to take account of ProxyProtocol settings...
85
listener = &proxyprotocol.Listener{
87
ProxyHeaderTimeout: setting.ProxyProtocolHeaderTimeout,
88
AcceptUnknown: setting.ProxyProtocolAcceptUnknown,
91
srv.listener = listener
93
srv.BeforeBegin(srv.network, srv.address)
95
return srv.Serve(serve)
98
// ListenAndServeTLSConfig listens on the provided network address and then calls
99
// Serve to handle requests on incoming TLS connections.
100
func (srv *Server) ListenAndServeTLSConfig(tlsConfig *tls.Config, serve ServeFunction, useProxyProtocol, proxyProtocolTLSBridging bool) error {
101
go srv.awaitShutdown()
103
if tlsConfig.MinVersion == 0 {
104
tlsConfig.MinVersion = tls.VersionTLS12
107
listener, err := GetListener(srv.network, srv.address)
109
log.Error("Unable to get Listener: %v", err)
113
// we need to wrap the listener to take account of our lifecycle
114
listener = newWrappedListener(listener, srv)
116
// Now we need to take account of ProxyProtocol settings... If we're not bridging then we expect that the proxy will forward the connection to us
117
if useProxyProtocol && !proxyProtocolTLSBridging {
118
listener = &proxyprotocol.Listener{
120
ProxyHeaderTimeout: setting.ProxyProtocolHeaderTimeout,
121
AcceptUnknown: setting.ProxyProtocolAcceptUnknown,
125
// Now handle the tls protocol
126
listener = tls.NewListener(listener, tlsConfig)
128
// Now if we're bridging then we need the proxy to tell us who we're bridging for...
129
if useProxyProtocol && proxyProtocolTLSBridging {
130
listener = &proxyprotocol.Listener{
132
ProxyHeaderTimeout: setting.ProxyProtocolHeaderTimeout,
133
AcceptUnknown: setting.ProxyProtocolAcceptUnknown,
137
srv.listener = listener
138
srv.BeforeBegin(srv.network, srv.address)
140
return srv.Serve(serve)
143
// Serve accepts incoming HTTP connections on the wrapped listener l, creating a new
144
// service goroutine for each. The service goroutines read requests and then call
145
// handler to reply to them. Handler is typically nil, in which case the
146
// DefaultServeMux is used.
148
// In addition to the standard Serve behaviour each connection is added to a
149
// sync.Waitgroup so that all outstanding connections can be served before shutting
151
func (srv *Server) Serve(serve ServeFunction) error {
152
defer log.Debug("Serve() returning... (PID: %d)", syscall.Getpid())
153
srv.setState(stateRunning)
154
GetManager().RegisterServer()
155
err := serve(srv.listener)
156
log.Debug("Waiting for connections to finish... (PID: %d)", syscall.Getpid())
158
srv.setState(stateTerminate)
159
GetManager().ServerDone()
160
// use of closed means that the listeners are closed - i.e. we should be shutting down - return nil
161
if err == nil || strings.Contains(err.Error(), "use of closed") || strings.Contains(err.Error(), "http: Server closed") {
167
func (srv *Server) getState() state {
169
defer srv.lock.RUnlock()
174
func (srv *Server) setState(st state) {
176
defer srv.lock.Unlock()
181
type filer interface {
182
File() (*os.File, error)
185
type wrappedListener struct {
191
func newWrappedListener(l net.Listener, srv *Server) *wrappedListener {
192
return &wrappedListener{
198
func (wl *wrappedListener) Accept() (net.Conn, error) {
200
// Set keepalive on TCPListeners connections.
201
if tcl, ok := wl.Listener.(*net.TCPListener); ok {
202
tc, err := tcl.AcceptTCP()
206
_ = tc.SetKeepAlive(true) // see http.tcpKeepAliveListener
207
_ = tc.SetKeepAlivePeriod(3 * time.Minute) // see http.tcpKeepAliveListener
211
c, err = wl.Listener.Accept()
223
perWriteTimeout: wl.server.PerWriteTimeout,
224
perWritePerKbTimeout: wl.server.PerWritePerKbTimeout,
231
func (wl *wrappedListener) Close() error {
233
return syscall.EINVAL
237
return wl.Listener.Close()
240
func (wl *wrappedListener) File() (*os.File, error) {
241
// returns a dup(2) - FD_CLOEXEC flag *not* set so the listening socket can be passed to child processes
242
return wl.Listener.(filer).File()
245
type wrappedConn struct {
250
perWriteTimeout time.Duration
251
perWritePerKbTimeout time.Duration
254
func (w *wrappedConn) Write(p []byte) (n int, err error) {
255
if w.perWriteTimeout > 0 {
256
minTimeout := time.Duration(len(p)/1024) * w.perWritePerKbTimeout
257
minDeadline := time.Now().Add(minTimeout).Add(w.perWriteTimeout)
259
w.deadline = w.deadline.Add(minTimeout)
260
if minDeadline.After(w.deadline) {
261
w.deadline = minDeadline
263
_ = w.Conn.SetWriteDeadline(w.deadline)
265
return w.Conn.Write(p)
268
func (w *wrappedConn) Close() error {
269
if atomic.CompareAndSwapInt32(w.closed, 0, 1) {
271
if err := recover(); err != nil {
273
case <-GetManager().IsHammer():
274
// Likely deadlocked request released at hammertime
275
log.Warn("Panic during connection close! %v. Likely there has been a deadlocked request which has been released by forced shutdown.", err)
277
log.Error("Panic during connection close! %v", err)
283
return w.Conn.Close()