24
"os"
25
"strconv"
26
"strings"
27
- "sync"
27
"sync/atomic"
28
"syscall"
30
- "time"
29
30
"github.com/lucas-clemente/quic-go"
31
"github.com/lucas-clemente/quic-go/http3"
41
// the socket have been finished. Always be sure to close listeners
42
// when you are done with them, just like normal listeners.
43
func Listen(network, addr string) (net.Listener, error) {
44
+ // a 0 timeout means Go uses its default
45
+ return ListenTimeout(network, addr, 0)
46
+}
47
+
48
+// getListenerFromPlugin returns a listener on the given network and address
49
+// if a plugin has registered the network name. It may return (nil, nil) if
50
+// no plugin can provide a listener.
51
+func getListenerFromPlugin(network, addr string) (net.Listener, error) {
52
network = strings.TrimSpace(strings.ToLower(network))
53
54
// get listener from plugin if network type is registered
57
return getListener(network, addr)
58
}
59
54
- lnKey := listenerKey(network, addr)
55
-
56
- sharedLn, _, err := listenerPool.LoadOrNew(lnKey, func() (Destructor, error) {
57
- ln, err := net.Listen(network, addr)
58
- if err != nil {
59
- // https://github.com/caddyserver/caddy/pull/4534
60
- if isUnixNetwork(network) && isListenBindAddressAlreadyInUseError(err) {
61
- return nil, fmt.Errorf("%w: this can happen if Caddy was forcefully killed", err)
62
- }
63
- return nil, err
64
- }
65
- return &sharedListener{Listener: ln, key: lnKey}, nil
66
- })
67
- if err != nil {
68
- return nil, err
69
- }
70
-
71
- return &fakeCloseListener{sharedListener: sharedLn.(*sharedListener)}, nil
60
+ return nil, nil
61
}
62
63
// ListenPacket returns a net.PacketConn suitable for use in a Caddy module.
113
}, err
114
}
115
127
-func listenerKey(network, addr string) string {
128
- return network + "/" + addr
129
-}
130
-
116
// ListenerUsage returns the current usage count of the given listener address.
117
func ListenerUsage(network, addr string) int {
118
count, _ := listenerPool.References(listenerKey(network, addr))
119
return count
120
}
121
137
-// fakeCloseListener is a private wrapper over a listener that
138
-// is shared. The state of fakeCloseListener is not shared.
139
-// This allows one user of a socket to "close" the listener
140
-// while in reality the socket stays open for other users of
141
-// the listener. In this way, servers become hot-swappable
142
-// while the listener remains running. Listeners should be
143
-// re-wrapped in a new fakeCloseListener each time the listener
144
-// is reused. This type is atomic and values must not be copied.
145
-type fakeCloseListener struct {
146
- closed int32 // accessed atomically; belongs to this struct only
147
- *sharedListener // embedded, so we also become a net.Listener
148
-}
149
-
150
-func (fcl *fakeCloseListener) Accept() (net.Conn, error) {
151
- // if the listener is already "closed", return error
152
- if atomic.LoadInt32(&fcl.closed) == 1 {
153
- return nil, fakeClosedErr(fcl)
154
- }
155
-
156
- // call underlying accept
157
- conn, err := fcl.sharedListener.Accept()
158
- if err == nil {
159
- return conn, nil
160
- }
161
-
162
- // since Accept() returned an error, it may be because our reference to
163
- // the listener (this fakeCloseListener) may have been closed, i.e. the
164
- // server is shutting down; in that case, we need to clear the deadline
165
- // that we set when Close() was called, and return a non-temporary and
166
- // non-timeout error value to the caller, masking the "true" error, so
167
- // that server loops / goroutines won't retry, linger, and leak
168
- if atomic.LoadInt32(&fcl.closed) == 1 {
169
- // we dereference the sharedListener explicitly even though it's embedded
170
- // so that it's clear in the code that side-effects are shared with other
171
- // users of this listener, not just our own reference to it; we also don't
172
- // do anything with the error because all we could do is log it, but we
173
- // expliclty assign it to nothing so we don't forget it's there if needed
174
- _ = fcl.sharedListener.clearDeadline()
175
-
176
- if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
177
- return nil, fakeClosedErr(fcl)
178
- }
179
- }
180
-
181
- return nil, err
182
-}
183
-
184
-// Close stops accepting new connections without closing the
185
-// underlying listener. The underlying listener is only closed
186
-// if the caller is the last known user of the socket.
187
-func (fcl *fakeCloseListener) Close() error {
188
- if atomic.CompareAndSwapInt32(&fcl.closed, 0, 1) {
189
- // There are two ways I know of to get an Accept()
190
- // function to return to the server loop that called
191
- // it: close the listener, or set a deadline in the
192
- // past. Obviously, we can't close the socket yet
193
- // since others may be using it (hence this whole
194
- // file). But we can set the deadline in the past,
195
- // and this is kind of cheating, but it works, and
196
- // it apparently even works on Windows.
197
- _ = fcl.sharedListener.setDeadline()
198
- _, _ = listenerPool.Delete(fcl.sharedListener.key)
199
- }
200
- return nil
122
+func listenerKey(network, addr string) string {
123
+ return network + "/" + addr
124
}
125
126
type fakeCloseQuicListener struct {
206
return nil, fmt.Errorf("SyscallConn() not implemented for %T", fcpc.PacketConn)
207
}
208
286
-// sharedListener is a wrapper over an underlying listener. The listener
287
-// and the other fields on the struct are shared state that is synchronized,
288
-// so sharedListener structs must never be copied (always use a pointer).
289
-type sharedListener struct {
290
- net.Listener
291
- key string // uniquely identifies this listener
292
- deadline bool // whether a deadline is currently set
293
- deadlineMu sync.Mutex
294
-}
295
-
296
-func (sl *sharedListener) clearDeadline() error {
297
- var err error
298
- sl.deadlineMu.Lock()
299
- if sl.deadline {
300
- switch ln := sl.Listener.(type) {
301
- case *net.TCPListener:
302
- err = ln.SetDeadline(time.Time{})
303
- case *net.UnixListener:
304
- err = ln.SetDeadline(time.Time{})
305
- }
306
- sl.deadline = false
307
- }
308
- sl.deadlineMu.Unlock()
309
- return err
310
-}
311
-
312
-func (sl *sharedListener) setDeadline() error {
313
- timeInPast := time.Now().Add(-1 * time.Minute)
314
- var err error
315
- sl.deadlineMu.Lock()
316
- if !sl.deadline {
317
- switch ln := sl.Listener.(type) {
318
- case *net.TCPListener:
319
- err = ln.SetDeadline(timeInPast)
320
- case *net.UnixListener:
321
- err = ln.SetDeadline(timeInPast)
322
- }
323
- sl.deadline = true
324
- }
325
- sl.deadlineMu.Unlock()
326
- return err
327
-}
328
-
329
-// Destruct is called by the UsagePool when the listener is
330
-// finally not being used anymore. It closes the socket.
331
-func (sl *sharedListener) Destruct() error {
332
- return sl.Listener.Close()
333
-}
334
-
209
// sharedQuicListener is like sharedListener, but for quic.EarlyListeners.
210
type sharedQuicListener struct {
211
quic.EarlyListener