summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYawning Angel <yawning@torproject.org>2015-03-28 03:09:17 +0000
committerYawning Angel <yawning@torproject.org>2015-03-28 03:09:17 +0000
commit402fe97d8547d216746d2237010f32b691cb71e1 (patch)
tree127608f71b1c8428a723b47769d5c91511ee1fdc
parent657c8e4f02ad6c6c3cc97256b7529fe5514c0945 (diff)
Add support for tor feature #15435.
If the relevant enviornment variable is set, treat read errors from Stdin as a SIGTERM.
-rw-r--r--ChangeLog1
-rw-r--r--obfs4proxy/pt_extras.go6
-rw-r--r--obfs4proxy/termmon.go56
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
}