aboutsummaryrefslogtreecommitdiffhomepage
path: root/listen.go
diff options
context:
space:
mode:
authorAaron Paterson <[email protected]>2024-09-30 12:55:03 -0400
committerGitHub <[email protected]>2024-09-30 10:55:03 -0600
commit4b1a9b6cc1aa521e21289afa276d29952a97d8f3 (patch)
treec4e28391860ed003aebaca340deb764b6f532e94 /listen.go
parent1a345b4fa620dfb0909a3b086bd76e35dfdbefa5 (diff)
downloadcaddy-4b1a9b6cc1aa521e21289afa276d29952a97d8f3.tar.gz
caddy-4b1a9b6cc1aa521e21289afa276d29952a97d8f3.zip
core: Implement socket activation listeners (#6573)
* caddy adapt for listen_protocols * adapt listen_socket * allow multiple listen sockets for port ranges and readd socket fd listen logic * readd logic to start servers according to listener protocols * gofmt * adapt caddytest * gosec * fmt and rename listen to listenWithSocket * fmt and rename listen to listenWithSocket * more consistent error msg * non unix listenReusableWithSocketFile * remove unused func * doc comment typo * nonosec * commit * doc comments * more doc comments * comment was misleading, cardinality did not change * addressesWithProtocols * update test * fd/ and fdgram/ * rm addr * actually write... * i guess we doin' "skip": now * wrong var in placeholder * wrong var in placeholder II * update param name in comment * dont save nil file pointers * windows * key -> parsedKey * osx * multiple default_bind with protocols * check for h1 and h2 listener netw
Diffstat (limited to 'listen.go')
-rw-r--r--listen.go80
1 files changed, 68 insertions, 12 deletions
diff --git a/listen.go b/listen.go
index 34812b54f..f5c2086a6 100644
--- a/listen.go
+++ b/listen.go
@@ -18,7 +18,11 @@ package caddy
import (
"context"
+ "fmt"
"net"
+ "os"
+ "slices"
+ "strconv"
"sync"
"sync/atomic"
"time"
@@ -31,10 +35,49 @@ func reuseUnixSocket(network, addr string) (any, error) {
}
func listenReusable(ctx context.Context, lnKey string, network, address string, config net.ListenConfig) (any, error) {
- switch network {
- case "udp", "udp4", "udp6", "unixgram":
+ var socketFile *os.File
+
+ fd := slices.Contains([]string{"fd", "fdgram"}, network)
+ if fd {
+ socketFd, err := strconv.ParseUint(address, 0, strconv.IntSize)
+ if err != nil {
+ return nil, fmt.Errorf("invalid file descriptor: %v", err)
+ }
+
+ func() {
+ socketFilesMu.Lock()
+ defer socketFilesMu.Unlock()
+
+ socketFdWide := uintptr(socketFd)
+ var ok bool
+
+ socketFile, ok = socketFiles[socketFdWide]
+
+ if !ok {
+ socketFile = os.NewFile(socketFdWide, lnKey)
+ if socketFile != nil {
+ socketFiles[socketFdWide] = socketFile
+ }
+ }
+ }()
+
+ if socketFile == nil {
+ return nil, fmt.Errorf("invalid socket file descriptor: %d", socketFd)
+ }
+ }
+
+ datagram := slices.Contains([]string{"udp", "udp4", "udp6", "unixgram", "fdgram"}, network)
+ if datagram {
sharedPc, _, err := listenerPool.LoadOrNew(lnKey, func() (Destructor, error) {
- pc, err := config.ListenPacket(ctx, network, address)
+ var (
+ pc net.PacketConn
+ err error
+ )
+ if fd {
+ pc, err = net.FilePacketConn(socketFile)
+ } else {
+ pc, err = config.ListenPacket(ctx, network, address)
+ }
if err != nil {
return nil, err
}
@@ -44,20 +87,27 @@ func listenReusable(ctx context.Context, lnKey string, network, address string,
return nil, err
}
return &fakeClosePacketConn{sharedPacketConn: sharedPc.(*sharedPacketConn)}, nil
+ }
- default:
- sharedLn, _, err := listenerPool.LoadOrNew(lnKey, func() (Destructor, error) {
- ln, err := config.Listen(ctx, network, address)
- if err != nil {
- return nil, err
- }
- return &sharedListener{Listener: ln, key: lnKey}, nil
- })
+ sharedLn, _, err := listenerPool.LoadOrNew(lnKey, func() (Destructor, error) {
+ var (
+ ln net.Listener
+ err error
+ )
+ if fd {
+ ln, err = net.FileListener(socketFile)
+ } else {
+ ln, err = config.Listen(ctx, network, address)
+ }
if err != nil {
return nil, err
}
- return &fakeCloseListener{sharedListener: sharedLn.(*sharedListener), keepAlivePeriod: config.KeepAlive}, nil
+ return &sharedListener{Listener: ln, key: lnKey}, nil
+ })
+ if err != nil {
+ return nil, err
}
+ return &fakeCloseListener{sharedListener: sharedLn.(*sharedListener), keepAlivePeriod: config.KeepAlive}, nil
}
// fakeCloseListener is a private wrapper over a listener that
@@ -260,3 +310,9 @@ var (
Unwrap() net.PacketConn
}) = (*fakeClosePacketConn)(nil)
)
+
+// socketFiles is a fd -> *os.File map used to make a FileListener/FilePacketConn from a socket file descriptor.
+var socketFiles = map[uintptr]*os.File{}
+
+// socketFilesMu synchronizes socketFiles insertions
+var socketFilesMu sync.Mutex