#!/bin/bash 

# assumption for CGC: only 1 file to be analyzed

if [ -z "$IDA_PRO_SERVER_HOST" ]; then echo Failed to set IDA_PRO_SERVER_HOST; exit 2; fi
if [ -z "$IDA_PRO_SERVER_USER" ]; then
    IDA_PRO_SERVER_USER=`whoami`
fi
if [ -z "$IDA_PRO_SERVER_PORT" ]; then
    IDA_PRO_SERVER_PORT=22
fi

if [ -z "$MAX_IDA_PROCESSES" ]; then
	MAX_IDA_PROCESSES=25
	echo "Max analysis processes not specified, set to $MAX_IDA_PROCESSES"
fi

if [ -z "$1" ]; then
	echo Failed to specify binary to be analyzed
	exit 3
fi

file=$1

md5name=$(md5sum $file | awk '{print $1}')
if [ -z "$md5name" ]; then 
	echo Failed to obtain md5 hash for file to be analyzed
	exit 4
fi

DIRECTORY=/tmp/remote-analyze/${md5name}

# in seconds
COPY_TIMEOUT=75
SIMPLE_TIMEOUT=10
ANALYZE_TIMEOUT=7200

verify_host_live()
{
	remotehost=$1

	echo "Verify host $remotehost is live"

	ssh -o ConnectTimeout=$SIMPLE_TIMEOUT -o BatchMode=yes -p $IDA_PRO_SERVER_PORT $IDA_PRO_SERVER_USER@$remotehost ls /tmp >/dev/null
	if [ ! $? -eq 0 ]; then
		return 1
	fi
	
	return 0
}

copy_STARS_info()
{
	remotehost=$1

	echo "Retrieve STARS info from host $remotehost"

	# Copy the answer back
	scp -o ConnectTimeout=$COPY_TIMEOUT -o BatchMode=yes -P $IDA_PRO_SERVER_PORT $IDA_PRO_SERVER_USER@$remotehost:${DIRECTORY}/a.ncexe.* .
	return $?
}

server_has_cached_info()
{
	remotehost=$1

	echo "Check whether STARS results already present from host $remotehost"

	# Copy the answer back
	ssh -o ConnectTimeout=$SIMPLE_TIMEOUT -o BatchMode=yes -p $IDA_PRO_SERVER_PORT $IDA_PRO_SERVER_USER@$remotehost ls -l ${DIRECTORY}/a.ncexe.infoannot > tmp.$$
	if [ -f tmp.$$ ]; then
		grep a.ncexe.infoannot tmp.$$
		if [ ! $? -eq 0 ]; then
			rm tmp.$$
			return 1
		else
			return 0
		fi
	fi
	return 1
}

copy_and_verify_result()
{
	remotehost=$1
	annotfile=$2

	echo "Copy and sanity check STARS results from host $remotehost"
	copy_STARS_info $remotehost

	lines=`cat $annotfile | wc -l`
	if [ $lines -lt 10 ]; then
		echo "Failed to produce a valid annotations file for $annotfile."
		return 1 
	fi

	return 0
}

cleanup_remote_host()
{
	remotehost=$1
	echo "Cleanup host $remotehost"
	ssh -o ConnectTimeout=$SIMPLE_TIMEOUT -o BatchMode=yes -p $IDA_PRO_SERVER_PORT $remotehost rm -f ${DIRECTORY}/a.i64
}

run_remote_command()
{
	remotehost=$1
	shift
	echo "Remote analyze on host $remotehost"

	# Create remote DIRECTORY
	ssh -o ConnectTimeout=$SIMPLE_TIMEOUT -o BatchMode=yes -p $IDA_PRO_SERVER_PORT $IDA_PRO_SERVER_USER@$remotehost mkdir -p ${DIRECTORY}

	# Check to see if the Ida Pro Server is too busy now and wait if necc.
	if [ -n "$MAX_IDA_PROCESSES" ]; then
		if [ `ssh -o ConnectTimeout=$SIMPLE_TIMEOUT -o BatchMode=yes -p $IDA_PRO_SERVER_PORT $IDA_PRO_SERVER_USER@$remotehost pgrep idal64|wc -l` -ge "$MAX_IDA_PROCESSES" ]; then
			echo "Remote server $remotehost too busy (max allowed: $MAX_IDA_PROCESSES) -- skip it"
			return 1
		fi
#	    while [ `ssh -o ConnectTimeout=$SIMPLE_TIMEOUT -o BatchMode=yes -p $IDA_PRO_SERVER_PORT $IDA_PRO_SERVER_USER@$remotehost pgrep idal64|wc -l` -ge "$MAX_IDA_PROCESSES" ]; do
#	        random=`od -An -N2 -tu2 /dev/urandom`
#	        # Wait 10-30 seconds
#		seconds=`expr $random % 20 + 10`
#		echo Waiting $seconds seconds for an IDA process to exit...
#		sleep $seconds
#	    done
	fi

	# Copy files to be processed to remote DIRECTORY
	scp -o ConnectTimeout=$COPY_TIMEOUT -o BatchMode=yes -P $IDA_PRO_SERVER_PORT -q $@ $IDA_PRO_SERVER_USER@$remotehost:$DIRECTORY
	if [ ! $? -eq 0 ]; then
		return 1
	fi

	# Give it max 2 hours for analysis
	ssh -o ConnectTimeout=$ANALYZE_TIMEOUT -o BatchMode=yes -p $IDA_PRO_SERVER_PORT $IDA_PRO_SERVER_USER@$remotehost "cd ~/techx_umbrella/peasoup; source set_env_vars; export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.; cd $DIRECTORY; screen -D -L -ln -m -a -T xterm sh -x "'$SMPSA_HOME'"/SMP-analyze.sh $@" 2>&1
	if [ ! $? -eq 0 ]; then
		return 1
	fi

	copy_and_verify_result $remotehost $file.annot
	rc=$?

	# cleanup_remote_host remote directory (a.i64)
	cleanup_remote_host $remotehost
	return $rc
}

# FIXME: need to handle multiple files to be analyzed?

exit_code=1

# try host 1
verify_host_live $IDA_PRO_SERVER_HOST
if [  $? -eq 0 ]; then
	server_has_cached_info $IDA_PRO_SERVER_HOST
	if [ $? -eq 0 ]; then
		echo SERVER HAS ALREADY ANALYZED $md5name, retrieving cached info
		copy_and_verify_result $remotehost $file.annot
		exit_code=$?
	fi

	if [ ! $exit_code -eq 0 ]; then
		run_remote_command $IDA_PRO_SERVER_HOST $@
		exit_code=$?
	fi
else
	echo "Host $IDA_PRO_SERVER_HOST is not responding"
fi

# if needed, try host 2
if [ ! $exit_code -eq 0 ]; then
	echo "Error detected on primary $IDA_PRO_SERVER_HOST, failing over to $IDA_PRO_SERVER_HOST2"
	verify_host_live $IDA_PRO_SERVER_HOST2
	if [ ! $? -eq 0 ]; then
		echo "Backup host $IDA_PRO_SERVER_HOST2 is not responding"
		exit 1
	fi

	server_has_cached_info $IDA_PRO_SERVER_HOST2
	if [ $? -eq 0 ]; then
		echo SERVER HAS ALREADY ANALYZED $md5name, retrieving cached info
		copy_and_verify_result $IDA_PRO_SERVER_HOST2 $file.annot
		exit_code=$?
	fi

	if [ ! $exit_code -eq 0 ]; then
		run_remote_command $IDA_PRO_SERVER_HOST2 $@
		exit_code=$?
	fi
fi

exit $exit_code
