summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Holt <mholt@users.noreply.github.com>2022-09-01 16:30:03 -0600
committerGitHub <noreply@github.com>2022-09-01 16:30:03 -0600
commit1edc1a45e3aee1f7d86b68c3ddaf2fd16ba8ab73 (patch)
tree70d05a7707eba64747cc6764e3378595cf946df6
parentcb849bd6648294feb42eac1081aece589f20eaf6 (diff)
core: Plugins can register listener networks (#5002)
* core: Plugins can register listener networks This can be useful for custom listeners. This feature/API is experimental and may change! * caddyhttp: Expose server listeners
-rw-r--r--listeners.go38
-rw-r--r--modules/caddyhttp/server.go8
2 files changed, 46 insertions, 0 deletions
diff --git a/listeners.go b/listeners.go
index 8698387..a95c98c 100644
--- a/listeners.go
+++ b/listeners.go
@@ -31,6 +31,7 @@ import (
"github.com/lucas-clemente/quic-go"
"github.com/lucas-clemente/quic-go/http3"
+ "go.uber.org/zap"
)
// Listen is like net.Listen, except Caddy's listeners can overlap
@@ -42,6 +43,14 @@ import (
// the socket have been finished. Always be sure to close listeners
// when you are done with them, just like normal listeners.
func Listen(network, addr string) (net.Listener, error) {
+ network = strings.TrimSpace(strings.ToLower(network))
+
+ // get listener from plugin if network type is registered
+ if getListener, ok := networkTypes[network]; ok {
+ Log().Debug("getting listener from plugin", zap.String("network", network))
+ return getListener(network, addr)
+ }
+
lnKey := listenerKey(network, addr)
sharedLn, _, err := listenerPool.LoadOrNew(lnKey, func() (Destructor, error) {
@@ -551,6 +560,35 @@ func JoinNetworkAddress(network, host, port string) string {
return a
}
+// RegisterNetwork registers a network type with Caddy so that if a listener is
+// created for that network type, getListener will be invoked to get the listener.
+// This should be called during init() and will panic if the network type is standard
+// or reserved, or if it is already registered. EXPERIMENTAL and subject to change.
+func RegisterNetwork(network string, getListener ListenerFunc) {
+ network = strings.TrimSpace(strings.ToLower(network))
+
+ if network == "tcp" || network == "tcp4" || network == "tcp6" ||
+ network == "udp" || network == "udp4" || network == "udp6" ||
+ network == "unix" || network == "unixpacket" || network == "unixgram" ||
+ strings.HasPrefix("ip:", network) || strings.HasPrefix("ip4:", network) || strings.HasPrefix("ip6:", network) {
+ panic("network type " + network + " is reserved")
+ }
+
+ if _, ok := networkTypes[strings.ToLower(network)]; ok {
+ panic("network type " + network + " is already registered")
+ }
+
+ networkTypes[network] = getListener
+}
+
+// ListenerFunc is a function that can return a listener given a network and address.
+// The listeners must be capable of overlapping: with Caddy, new configs are loaded
+// before old ones are unloaded, so listeners may overlap briefly if the configs
+// both need the same listener. EXPERIMENTAL and subject to change.
+type ListenerFunc func(network, addr string) (net.Listener, error)
+
+var networkTypes = map[string]ListenerFunc{}
+
// ListenerWrapper is a type that wraps a listener
// so it can modify the input listener's methods.
// Modules that implement this interface are found
diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go
index dcf9af1..e01e7c8 100644
--- a/modules/caddyhttp/server.go
+++ b/modules/caddyhttp/server.go
@@ -579,6 +579,14 @@ func (s *Server) protocol(proto string) bool {
return false
}
+// Listeners returns the server's listeners. These are active listeners,
+// so calling Accept() or Close() on them will probably break things.
+// They are made available here for read-only purposes (e.g. Addr())
+// and for type-asserting for purposes where you know what you're doing.
+//
+// EXPERIMENTAL: Subject to change or removal.
+func (s *Server) Listeners() []net.Listener { return s.listeners }
+
// ServerLogConfig describes a server's logging configuration. If
// enabled without customization, all requests to this server are
// logged to the default logger; logger destinations may be