Skip to content

Instantly share code, notes, and snippets.

@basinilya
Last active April 14, 2024 10:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save basinilya/ac9cdadfe53807d562e02e1ee4de96f9 to your computer and use it in GitHub Desktop.
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
#!/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=3129
#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