From 86e2d1b0a48fbd84590291969611f1870471c3e0 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Tue, 26 Mar 2019 15:45:51 -0600 Subject: Rudimentary start of HTTP servers --- listeners.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 listeners.go (limited to 'listeners.go') diff --git a/listeners.go b/listeners.go new file mode 100644 index 0000000..962cb1d --- /dev/null +++ b/listeners.go @@ -0,0 +1,51 @@ +package caddy2 + +import ( + "fmt" + "net" + "sync/atomic" +) + +// Listen returns a listener suitable for use in a Caddy module. +func Listen(proto, addr string) (net.Listener, error) { + ln, err := net.Listen(proto, addr) + if err != nil { + return nil, err + } + return &fakeCloseListener{Listener: ln}, nil +} + +// fakeCloseListener's Close() method is a no-op. This allows +// stopping servers that are using the listener without giving +// up the socket; thus, servers become hot-swappable while the +// listener remains running. Listeners should be re-wrapped in +// a new fakeCloseListener each time the listener is reused. +type fakeCloseListener struct { + closed int32 + net.Listener +} + +// Accept accepts connections until Close() is called. +func (fcl *fakeCloseListener) Accept() (net.Conn, error) { + if atomic.LoadInt32(&fcl.closed) == 1 { + return nil, ErrSwappingServers + } + return fcl.Listener.Accept() +} + +// Close stops accepting new connections, but does not +// actually close the underlying listener. +func (fcl *fakeCloseListener) Close() error { + atomic.StoreInt32(&fcl.closed, 1) + return nil +} + +// CloseUnderlying actually closes the underlying listener. +func (fcl *fakeCloseListener) CloseUnderlying() error { + return fcl.Listener.Close() +} + +// ErrSwappingServers is returned by fakeCloseListener when +// Close() is called, indicating that it is pretending to +// be closed so that the server using it can terminate. +var ErrSwappingServers = fmt.Errorf("listener 'closed' 😉") -- cgit v1.2.3