chiark / gitweb /
bin/outbound: Change how we wait for SSH tunnels to end.
[tunneluser] / bin / outbound
CommitLineData
b16ea8ba
MW
1#! /bin/sh
2
3set -e
4case $# in
5 2) ;;
6 *) echo >&2 "usage: $0 {start|stop|restart|status} HOST"; exit 1 ;;
7esac
8op=$1 host=$2
9
10writefile () {
11 file=$1; shift
12 echo "$*" >"$file.new"
13 mv "$file.new" "$file"
14}
15
16runssh () { ssh -T -oControlPath="./$host.ctrl" "$@"; }
17
1dc744ac 18clobber () {
b16ea8ba
MW
19
20 ## Shut down an existing connection if there is one.
21 if [ -S "$host.ctrl" ]; then
22 runssh -Oexit "$host" >/dev/null 2>/dev/null || :
23 fi
24
25 ## If there's still a socket, then work out what to do.
26 if [ -e "$host.ctrl" ]; then
27
28 ## If the connection's still running then we have a problem.
29 if runssh -Ocheck "$host" >/dev/null 2>/dev/null; then
30 echo >&2 "$0: failed to kill existing connection to $host"
31 exit 2
32 fi
33
34 ## Remove the stale socket.
35 rm -f "$host.ctrl"
36 fi
1dc744ac
MW
37}
38
39stopit () {
40
41 ## Initial shutdown protocol.
42 writefile "$host.state" stopping
43 if [ -f "$host.pid" ]; then kill $(cat "$host.pid") 2>/dev/null || :; fi
44 rm -f "$host.pid"
45
46 ## Clobber the existing connection, if there is one.
47 clobber
b16ea8ba
MW
48
49 ## Update the state.
50 rm -f "$host.state" "$host.pid"
51}
52
53daemon () {
54
55 ## There doesn't seem to be a better way of getting this. :-(
56 read pid <"$host.daemonpipe"
57 rm -f "$host.daemonpipe"
58
59 ## Set up shop.
60 trap 'rm -f "$host.pid"; stopit' EXIT INT TERM
61 writefile "$host.pid" "$pid"
62
63 ## Initial delay.
64 delay=0
65
f93e3eb3
MW
66 ## Not waiting on a pipe yet.
67 kidcat=nil
68
b16ea8ba
MW
69 ## Keep the connection up for as long as we can.
70 while [ -f "$host.pid" ]; do
71
72 ## Maybe back off before trying another connection.
73 case $delay in
74 0)
75 delay=1
76 ;;
77 *)
78 writefile "$host.state" \
79 "wait until $(date -d+${delay}sec +"%Y-%m-%d %H:%M:%S %z")"
80 sleep $delay
81 delay=$(( 2*$delay ))
82 if [ $delay -gt 120 ]; then delay=120; fi
83 ;;
84 esac
85
f93e3eb3
MW
86 ## Prepare a pipe so that we can wait for SSH to finish. This is a
87 ## rotten hack.
88 case $kidcat in
89 nil) ;;
90 *) kill $kidcat >/dev/null 2>&1 || :; kidcat=nil ;;
91 esac
92 rm -f "$host.pipe"; mkfifo -m600 "$host.pipe"
93 cat $host.pipe >/dev/null& kidcat=$!
94
b16ea8ba
MW
95 ## Start a new connection.
96 writefile "$host.state" starting
f93e3eb3 97 if ! runssh -MNnf "$host" >"$host.pipe"; then continue; fi
b16ea8ba
MW
98 if ! runssh -Ocheck "$host" >/dev/null 2>&1; then
99 echo "connection to $host apparently stillborn"
100 continue
101 fi
102 writefile "$host.state" connected
103 delay=0
104
f93e3eb3
MW
105 ## Wait until it gets torn down.
106 wait $kidcat >/dev/null 2>&1 || :
b16ea8ba 107 rm -f "$host.pipe"
f93e3eb3 108 clobber
b16ea8ba
MW
109 writefile "$host.state" disconnected
110 done
111}
112
113startit () {
114
115 ## If there's already a connection then we have nothing to do.
116 if runssh -Ocheck "$host" >/dev/null 2>/dev/null; then
117 echo >&2 "$0: already connected to $host"
118 exit 0
119 fi
120
121 ## Start a daemon which makes connections for us. This is remarkably
122 ## tricky.
123 rm -f "$host.daemonpipe"; mkfifo -m600 "$host.daemonpipe"
124 { daemon& echo $! >"$host.daemonpipe"; } 2>&1 | logger -pdaemon.notice&
125}
126
127## Main dispatch.
128case "$op" in
129 start) startit ;;
130 stop) stopit ;;
131 restart) stopit; startit ;;
132 status)
133 if [ -f "$host.state" ]
134 then cat "$host.state"
135 else echo "down"
136 fi
137 ;;
138 *)
139 echo >&2 "usage: $0 {start|stop|restart|status} HOST"
140 exit 1
141 ;;
142esac