#!/bin/bash
#
# Test NBD client unexpected disconnect
#
# Copyright Red Hat, Inc. 2014
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

# creator
owner=stefanha@redhat.com

seq=`basename $0`
echo "QA output created by $seq"

here=`pwd`
status=1	# failure is the default!

_cleanup()
{
	rm -f nbd.sock
	rm -f nbd-fault-injector.out
	rm -f nbd-fault-injector.conf
}
trap "_cleanup; exit \$status" 0 1 2 3 15

# get standard environment, filters and checks
. ./common.rc
. ./common.filter

_supported_fmt generic
_supported_proto nbd
_supported_os Linux

check_disconnect() {
	local event export_name=foo extra_args nbd_addr nbd_url proto when

	while true; do
		case $1 in
		--classic-negotiation)
			shift
			extra_args=--classic-negotiation
			export_name=
			;;
		--tcp)
			shift
			proto=tcp
			;;
		--unix)
			shift
			proto=unix
			;;
		*)
			break
			;;
		esac
	done

	event=$1
	when=$2
	echo "=== Check disconnect $when $event ==="
	echo

	cat > "$TEST_DIR/nbd-fault-injector.conf" <<EOF
[inject-error]
event=$event
when=$when
EOF

	if [ "$proto" = "tcp" ]; then
		nbd_addr="127.0.0.1:0"
	else
		nbd_addr="$TEST_DIR/nbd.sock"
	fi

	rm -f "$TEST_DIR/nbd.sock"

	$PYTHON nbd-fault-injector.py $extra_args "$nbd_addr" "$TEST_DIR/nbd-fault-injector.conf" >"$TEST_DIR/nbd-fault-injector.out" 2>&1 &

	# Wait for server to be ready
	while ! grep -q 'Listening on ' "$TEST_DIR/nbd-fault-injector.out"; do
		sleep 0.1
	done

	# Extract the final address (port number has now been assigned in tcp case)
	nbd_addr=$(sed 's/Listening on \(.*\)$/\1/' "$TEST_DIR/nbd-fault-injector.out")

	if [ "$proto" = "tcp" ]; then
		nbd_url="nbd+tcp://$nbd_addr/$export_name"
	else
		nbd_url="nbd+unix:///$export_name?socket=$nbd_addr"
	fi

	$QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd

	echo
}

for proto in tcp unix; do
	for event in neg1 "export" neg2 request reply data; do
		for when in before after; do
			check_disconnect "--$proto" "$event" "$when"
		done

		# Also inject short replies from the NBD server
		case "$event" in
		neg1)
			for when in 8 16; do
				check_disconnect "--$proto" "$event" "$when"
			done
			;;
		"export")
			for when in 4 12 16; do
				check_disconnect "--$proto" "$event" "$when"
			done
			;;
		neg2)
			for when in 8 10; do
				check_disconnect "--$proto" "$event" "$when"
			done
			;;
		reply)
			for when in 4 8; do
				check_disconnect "--$proto" "$event" "$when"
			done
			;;
		esac
	done

	# Also check classic negotiation without export information
	for when in before 8 16 24 28 after; do
		check_disconnect "--$proto" --classic-negotiation "neg-classic" "$when"
	done
done

# success, all done
echo "*** done"
rm -f $seq.full
status=0
