From 4f94abae1b793e59a7c87ec073d1855a262cb268 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Sat, 2 Dec 2017 13:19:53 +0100
Subject: Support socket activation
---
main.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 53 insertions(+), 4 deletions(-)
diff --git a/main.go b/main.go
index efd0978..ca80f42 100644
--- a/main.go
+++ b/main.go
@@ -8,11 +8,14 @@ import (
"io"
"io/ioutil"
"log"
+ "net"
"net/http"
"os"
"path"
"regexp"
+ "strconv"
"strings"
+ "syscall"
"time"
"unicode/utf8"
)
@@ -245,13 +248,59 @@ func proxy(w http.ResponseWriter, req *http.Request) {
}
}
+// https://www.freedesktop.org/software/systemd/man/sd_listen_fds.html
+func socketActivationListener() net.Listener {
+ pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
+ if err != nil || pid != os.Getpid() {
+ return nil
+ }
+
+ nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS"))
+ if err != nil || nfds == 0 {
+ return nil
+ } else if nfds > 1 {
+ log.Fatalln("not supporting more than one listening socket")
+ }
+
+ const firstListenFd = 3
+ syscall.CloseOnExec(firstListenFd)
+ ln, err := net.FileListener(os.NewFile(firstListenFd, "socket activation"))
+ if err != nil {
+ log.Fatalln(err)
+ }
+ return ln
+}
+
+// Had to copy this from Server.ListenAndServe()
+type tcpKeepAliveListener struct{ *net.TCPListener }
+
+func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
+ tc, err := ln.AcceptTCP()
+ if err != nil {
+ return
+ }
+ _ = tc.SetKeepAlive(true)
+ _ = tc.SetKeepAlivePeriod(3 * time.Minute)
+ return tc, nil
+}
+
func main() {
- // TODO: also try to support systemd socket activation
- address := ":8000"
+ listenAddr := ":8000"
if len(os.Args) == 2 {
- address = os.Args[1]
+ listenAddr = os.Args[1]
+ }
+
+ var listener net.Listener
+ if ln := socketActivationListener(); listener != nil {
+ // Keepalives can be set in the systemd unit, see systemd.socket(5)
+ listener = ln
+ } else if ln, err := net.Listen("tcp", listenAddr); err != nil {
+ log.Fatalln(err)
+ } else {
+ listener = tcpKeepAliveListener{ln.(*net.TCPListener)}
}
http.HandleFunc("/", proxy)
- log.Fatal(http.ListenAndServe(address, nil))
+ // We don't need to clean up properly since we store no data
+ log.Fatalln(http.Serve(listener, nil))
}
--
cgit v1.2.3-70-g09d2