Last active
October 28, 2024 19:12
-
-
Save basinilya/ac9cdadfe53807d562e02e1ee4de96f9 to your computer and use it in GitHub Desktop.
https://stackoverflow.com/q/68469752/447503 svnsync cannot recover from source idle disconnect
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# usage: | |
# socat TCP-LISTEN:3128,reuseaddr,fork EXEC:"./hugebuf.sh -p",nofork | |
set -e | |
proxymode= | |
case $1 in | |
-p) | |
proxymode=x | |
;; | |
esac | |
if [ "$proxymode" ]; then | |
if [ $# -ne 1 ]; then | |
>&2 echo "No extra arguments expected in proxy mode" | |
exit 1 | |
fi | |
else | |
host=${1:?} | |
port=${2:?} | |
fi | |
WAITCMD= | |
NAME="<" | |
fn_log() { | |
>&2 printf '%(%c)T %s\n' -1 "$*" | |
} | |
fn_cleanup() { | |
fn_log "$NAME cleanup" | |
exec 4>&- | |
$WAITCMD | |
fn_log "$NAME exiting" | |
} | |
fn_wait_graceful() { | |
fn_log "$NAME received EOF from upstream; waiting for the other side: ${OTHERPID:?}" | |
sleep 60 & | |
#fn_log "$NAME" wait -n ${OTHERPID:?} $! | |
wait -n -p DEADPID ${OTHERPID:?} $! | |
if [ x"$DEADPID" != x"${OTHERPID:?}" ]; then | |
fn_log "$NAME killing the other side: ${OTHERPID:?}" | |
kill -KILL ${OTHERPID:?} $! 2>/dev/null || true | |
fi | |
} | |
# TODO: do not use -KILL, otherwise a grandchild may survive | |
fn_kill() { | |
fn_log "$NAME read failed; killing the other side" | |
kill -KILL ${OTHERPID:?} 2>/dev/null || true | |
} | |
# parent process is upstream reader, it pumps data with `pv` | |
# child process is upstream writer, it pumps data with `socat` | |
# '>' prefixes upstream writer logs or HTTP proxy request | |
# '<' prefixes upstream reader logs or HTTP proxy response | |
if [ "$proxymode" ]; then | |
fn_log "reading CONNECT request..." | |
<&0 read -r line | |
line=${line%$'\r'} | |
fn_log "> $line" | |
case $line in | |
'CONNECT '*' HTTP'*) | |
x=${line#* } | |
hostport=${x%% *} | |
host=${hostport%:*} | |
port=${hostport:${#host}} | |
port=${port#:} | |
;; | |
*) | |
fn_log "invalid request" | |
;; | |
esac | |
while true; do | |
<&0 read -r line | |
line=${line%$'\r'} | |
fn_log "> $line" | |
[ -n "$line" ] || break | |
done | |
# | |
fi | |
fn_log "upstream reader pid: $$" | |
OTHERPID=$$ | |
socketpeerhost=$host | |
socketpeerport=$port | |
# Since 2024-03-05 Mendix Team Server blocks connections from Russia | |
parentproxyhost=basin | |
parentproxyport=3130 | |
#parentproxyhost= | |
if [ x"$parentproxyhost" != x"" ]; then | |
socketpeerhost=${parentproxyhost} | |
socketpeerport=${parentproxyport} | |
fi | |
fn_log "connecting to ${socketpeerhost:?}:${socketpeerport}" | |
exec 4>"/dev/tcp/${socketpeerhost:?}/${socketpeerport}" | |
if [ x"$parentproxyhost" != x"" ]; then | |
>&4 printf 'CONNECT %s:%s HTTP/1.1\r\n' "${host:?}" "${port:?}" | |
>&4 printf '\r\n' | |
while true; do | |
<&4 read -r line | |
line=${line%$'\r'} | |
#fn_log "> $line" | |
[ -n "$line" ] || break | |
done | |
fi | |
if [ "$proxymode" ]; then | |
fn_proxyresponseline() { | |
fn_log "< $1" | |
>&1 printf '%s\r\n' "$1" | |
} | |
fn_proxyresponseline "HTTP/1.0 200 Connection Established" | |
fn_proxyresponseline "Proxy-agent: hugebuf.sh" | |
fn_proxyresponseline "" | |
fi | |
# TODO: do not use `wait`, use coproc and read with timeout to confirm the other side death | |
{ | |
trap 'fn_cleanup' EXIT | |
NAME=">" | |
WAITCMD=fn_kill | |
# override graceful wait command because we can't POSIX wait for parent | |
fn_wait_graceful() { | |
fn_log "$NAME received EOF from my client; waiting for the other side: ${OTHERPID:?}" | |
for ((i=0;i<60;i++)); do | |
# check OTHERPID still exists | |
kill -0 ${OTHERPID:?} 2>/dev/null || { | |
fn_log "$NAME the other side no longer exists: ${OTHERPID:?}, exiting" | |
return | |
} | |
sleep 1 | |
done | |
fn_log "$NAME killing the other side: ${OTHERPID:?}" | |
kill -KILL ${OTHERPID:?} 2>/dev/null || true | |
} | |
# unlike cat socat will hopefully shutdown the socket instead of closing it | |
fn_log "$NAME upstream writer started" | |
socat -u FD:0 FD:1,shut-down <&0 >&4 | |
# closing the FDs won't terminate the connection because the parent process has same FDs | |
# but we need to close them so they're not inherited by the killer | |
exec 0<&- 4>&- | |
# start killer | |
{ | |
# EXIT trap is not inherited | |
WAITCMD=fn_wait_graceful | |
fn_cleanup | |
} & | |
# no error | |
trap '' EXIT | |
} <&0 & | |
OTHERPID=$! | |
fn_log "upstream writer pid: ${OTHERPID:?}" | |
trap 'fn_cleanup' EXIT | |
WAITCMD=fn_kill | |
fn_log "$NAME upstream reader started" | |
pv --force -C -B8G -N $'\nabcdefgh' -F '%N %t %T %b' <&4 | |
socat -u FD:0 FD:1,shut-down </dev/null | |
WAITCMD=fn_wait_graceful |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment