64 lines
1.8 KiB
Go
64 lines
1.8 KiB
Go
// Copyright (C) 2023-2024 Umorpha Systems
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
sd "git.lukeshu.com/go/libsystemd/sd_daemon"
|
|
)
|
|
|
|
// netListen is like [net.Listen], but with support for our special
|
|
// "fd" address family.
|
|
//
|
|
// The purpose of doing this is that for development I really want to
|
|
// be able to have it listen on a TCP port, but for actual deployment
|
|
// I want it to be able to accept an already-opened socket from
|
|
// systemd, and so I wrote a reasonably genereral solution.
|
|
//
|
|
// Did I avoid unnecessary complexity writing special-purpose code, or
|
|
// did I introduce it by failing to remember that YAGNI?
|
|
func netListen(stype, saddr string) (net.Listener, error) {
|
|
switch stype {
|
|
case "fd":
|
|
switch saddr {
|
|
case "stdin", "0":
|
|
return net.FileListener(os.Stdin)
|
|
case "stdout", "1":
|
|
return net.FileListener(os.Stdout)
|
|
case "stderr", "2":
|
|
return net.FileListener(os.Stderr)
|
|
case "systemd":
|
|
sdFds := sd.ListenFds(true)
|
|
if len(sdFds) == 0 {
|
|
return nil, fmt.Errorf("fd:systemd given, but no systemd file descriptors passed in")
|
|
}
|
|
return net.FileListener(sdFds[0])
|
|
default:
|
|
if fd, _ := strconv.Atoi(saddr); fd > 0 {
|
|
return net.FileListener(os.NewFile(uintptr(fd), fmt.Sprintf("/dev/fd/%d", fd)))
|
|
}
|
|
if name, ok := strings.CutPrefix(saddr, "systemd:"); ok {
|
|
sdFiles := sd.ListenFds(true)
|
|
for _, file := range sdFiles {
|
|
if file.Name() == name {
|
|
return net.FileListener(file)
|
|
}
|
|
}
|
|
if n, err := strconv.Atoi(name); err == nil && n >= 0 && n < len(sdFiles) {
|
|
return net.FileListener(sdFiles[n])
|
|
}
|
|
return nil, fmt.Errorf("does not match any systemd file descriptor: %q", name)
|
|
}
|
|
return nil, fmt.Errorf("invalid file descriptor name: %q", saddr)
|
|
}
|
|
default:
|
|
return net.Listen(stype, saddr)
|
|
}
|
|
}
|