commit 402fe97d8547d216746d2237010f32b691cb71e1 Author: Yawning Angel yawning@torproject.org Date: Sat Mar 28 03:09:17 2015 +0000
Add support for tor feature #15435.
If the relevant enviornment variable is set, treat read errors from Stdin as a SIGTERM. --- ChangeLog | 1 + obfs4proxy/pt_extras.go | 6 +++++ obfs4proxy/termmon.go | 56 +++++++++++++++++++++++++++++------------------ 3 files changed, 42 insertions(+), 21 deletions(-)
diff --git a/ChangeLog b/ChangeLog index 5e77d16..ce868b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ Changes in version 0.0.5 - UNRELEASED: - Go vet/fmt fixes, and misc. code cleanups. Patches by mvdan. - Changed the go.net import path to the new location (golang.org/x/net). - Added limited support for detecting if the parent process crashes. + - Support for tor feature #15335 (stdin based termination notification).
Changes in version 0.0.4 - 2015-02-17 - Improve the runtime performance of the obfs4 handshake tests. diff --git a/obfs4proxy/pt_extras.go b/obfs4proxy/pt_extras.go index 9eddd26..f490fbc 100644 --- a/obfs4proxy/pt_extras.go +++ b/obfs4proxy/pt_extras.go @@ -158,3 +158,9 @@ func resolveAddrStr(addrStr string) (*net.TCPAddr, error) {
return &net.TCPAddr{IP: ip, Port: int(port), Zone: ""}, nil } + +// Feature #15435 adds a new env var for determining if Tor keeps stdin +// open for use in termination detection. +func ptShouldExitOnStdinClose() bool { + return os.Getenv("TOR_PT_EXIT_ON_STDIN_CLOSE") == "1" +} diff --git a/obfs4proxy/termmon.go b/obfs4proxy/termmon.go index eac7e20..186293c 100644 --- a/obfs4proxy/termmon.go +++ b/obfs4proxy/termmon.go @@ -28,6 +28,8 @@ package main
import ( + "io" + "io/ioutil" "os" "os/signal" "runtime" @@ -68,6 +70,17 @@ func (m *termMonitor) wait(termOnNoHandlers bool) os.Signal { } }
+func (m *termMonitor) termOnStdinClose() { + _, err := io.Copy(ioutil.Discard, os.Stdin) + + // io.Copy() will return a nil on EOF, since reaching EOF is + // expected behavior. No matter what, if this unblocks, assume + // that stdin is closed, and treat that as having received a + // SIGTERM. + noticef("Stdin is closed or unreadable: %v", err) + m.sigChan <- syscall.SIGTERM +} + func (m *termMonitor) termOnPPIDChange(ppid int) { // Under most if not all U*IX systems, the parent PID will change // to that of init once the parent dies. There are several notable @@ -77,7 +90,6 @@ func (m *termMonitor) termOnPPIDChange(ppid int) { // Naturally we lose if the parent has died by the time when the // Getppid() call was issued in our parent, but, this is better // than nothing. - const ppidPollInterval = 1 * time.Second for ppid == os.Getppid() { time.Sleep(ppidPollInterval) @@ -89,31 +101,33 @@ func (m *termMonitor) termOnPPIDChange(ppid int) { m.sigChan <- syscall.SIGTERM }
-func newTermMonitor() *termMonitor { +func newTermMonitor() (m *termMonitor) { ppid := os.Getppid() - m := new(termMonitor) + m = new(termMonitor) m.sigChan = make(chan os.Signal) m.handlerChan = make(chan int) signal.Notify(m.sigChan, syscall.SIGINT, syscall.SIGTERM)
- // Until #15435 is implemented, there is no reliable way to see if - // the parent has died that is portable/platform independent/reliable. - // - // Do the next best thing and use various kludges and hacks: - // * Linux - Platform specific code that should always work. - // * Other U*IX - Somewhat generic code, that works unless the parent - // dies before the monitor is initialized. - // * Windows - Don't specifically monitor for parent termination. - if termMonitorOSInit != nil { - // Errors here are non-fatal, since it might still be possible - // to fall back to a generic implementation. - if err := termMonitorOSInit(m); err == nil { - return m + // If tor supports feature #15435, we can use Stdin being closed as an + // indication that tor has died, or wants the PT to shutdown for any + // reason. + if ptShouldExitOnStdinClose() { + go m.termOnStdinClose() + } else { + // Instead of feature #15435, use various kludges and hacks: + // * Linux - Platform specific code that should always work. + // * Other U*IX - Somewhat generic code, that works unless the + // parent dies before the monitor is initialized. + if termMonitorOSInit != nil { + // Errors here are non-fatal, since it might still be + // possible to fall back to a generic implementation. + if err := termMonitorOSInit(m); err == nil { + return + } + } + if runtime.GOOS != "windows" { + go m.termOnPPIDChange(ppid) } } - if runtime.GOOS != "windows" { - go m.termOnPPIDChange(ppid) - } - - return m + return }
tor-commits@lists.torproject.org