From 35ddf435059fb3f4a9a2903a5235622fe3d3a590 Mon Sep 17 00:00:00 2001 From: Star Brilliant Date: Tue, 27 Nov 2018 17:37:57 +0800 Subject: [PATCH] Add PID file support --- doh-client/main.go | 67 ++++++++++++++++++++++++++++++++++++++++++++++ doh-server/main.go | 67 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/doh-client/main.go b/doh-client/main.go index 83fb2d0..14a5392 100644 --- a/doh-client/main.go +++ b/doh-client/main.go @@ -25,14 +25,81 @@ package main import ( "flag" + "fmt" + "io" + "io/ioutil" "log" + "os" + "runtime" + "strconv" ) +func checkPIDFile(pidFile string) (bool, error) { +retry: + f, err := os.OpenFile(pidFile, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666) + if os.IsExist(err) { + pidStr, err := ioutil.ReadFile(pidFile) + if err != nil { + return false, err + } + pid, err := strconv.ParseUint(string(pidStr), 10, 0) + if err != nil { + return false, err + } + _, err = os.Stat(fmt.Sprintf("/proc/%d", pid)) + if os.IsNotExist(err) { + err = os.Remove(pidFile) + if err != nil { + return false, err + } + goto retry + } else if err != nil { + return false, err + } + log.Printf("Already running on PID %d, exiting.\n", pid) + return false, nil + } else if err != nil { + return false, err + } + defer f.Close() + _, err = io.WriteString(f, strconv.FormatInt(int64(os.Getpid()), 10)) + if err != nil { + return false, err + } + return true, nil +} + func main() { confPath := flag.String("conf", "doh-client.conf", "Configuration file") verbose := flag.Bool("verbose", false, "Enable logging") + showVersion := flag.Bool("version", false, "Show software version and exit") + var pidFile *string + + // I really want to push the technology forward by recommending cgroup-based + // process tracking. But I understand some cloud service providers have + // their own monitoring system. So this feature is only enabled on Linux and + // BSD series platforms which lacks functionality similar to cgroup. + if runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd" || runtime.GOOS == "linux" || runtime.GOOS == "netbsd" || runtime.GOOS == "openbsd" { + pidFile = flag.String("pid-file", "", "PID file for legacy supervision systems lacking support for reliable cgroup-based process tracking") + } + flag.Parse() + if *showVersion { + fmt.Printf("doh-server %s\nHomepage: https://github.com/m13253/dns-over-https\n", VERSION) + return + } + + if pidFile != nil && *pidFile != "" { + ok, err := checkPIDFile(*pidFile) + if err != nil { + log.Printf("Error checking PID file: %v\n", err) + } + if !ok { + return + } + } + conf, err := loadConfig(*confPath) if err != nil { log.Fatalln(err) diff --git a/doh-server/main.go b/doh-server/main.go index 5e970cb..fcd8fc2 100644 --- a/doh-server/main.go +++ b/doh-server/main.go @@ -25,14 +25,81 @@ package main import ( "flag" + "fmt" + "io" + "io/ioutil" "log" + "os" + "runtime" + "strconv" ) +func checkPIDFile(pidFile string) (bool, error) { +retry: + f, err := os.OpenFile(pidFile, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666) + if os.IsExist(err) { + pidStr, err := ioutil.ReadFile(pidFile) + if err != nil { + return false, err + } + pid, err := strconv.ParseUint(string(pidStr), 10, 0) + if err != nil { + return false, err + } + _, err = os.Stat(fmt.Sprintf("/proc/%d", pid)) + if os.IsNotExist(err) { + err = os.Remove(pidFile) + if err != nil { + return false, err + } + goto retry + } else if err != nil { + return false, err + } + log.Printf("Already running on PID %d, exiting.\n", pid) + return false, nil + } else if err != nil { + return false, err + } + defer f.Close() + _, err = io.WriteString(f, strconv.FormatInt(int64(os.Getpid()), 10)) + if err != nil { + return false, err + } + return true, nil +} + func main() { confPath := flag.String("conf", "doh-server.conf", "Configuration file") verbose := flag.Bool("verbose", false, "Enable logging") + showVersion := flag.Bool("version", false, "Show software version and exit") + var pidFile *string + + // I really want to push the technology forward by recommending cgroup-based + // process tracking. But I understand some cloud service providers have + // their own monitoring system. So this feature is only enabled on Linux and + // BSD series platforms which lacks functionality similar to cgroup. + if runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd" || runtime.GOOS == "linux" || runtime.GOOS == "netbsd" || runtime.GOOS == "openbsd" { + pidFile = flag.String("pid-file", "", "PID file for legacy supervision systems lacking support for reliable cgroup-based process tracking") + } + flag.Parse() + if *showVersion { + fmt.Printf("doh-server %s\nHomepage: https://github.com/m13253/dns-over-https\n", VERSION) + return + } + + if pidFile != nil && *pidFile != "" { + ok, err := checkPIDFile(*pidFile) + if err != nil { + log.Printf("Error checking PID file: %v\n", err) + } + if !ok { + return + } + } + conf, err := loadConfig(*confPath) if err != nil { log.Fatalln(err)