#!/bin/sh
OPATH="/tmp/"
TCPDUMP=''
PPLAYS=''
PORT="0"
PROG=$(command -v pplay.py)
if [ -z "$PROG" ]; then
  PROG="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)/pplay.py"
fi
VERBOSE=0
OUTPUT_FILE=''
SERVER_LOG=$(mktemp /tmp/smcap2pcap-server.XXXXXX)
TCPDUMP_LOG=$(mktemp /tmp/smcap2pcap-tcpdump.XXXXXX)

cleanup() {
  [ -n "$TCPDUMP" ] && kill -INT "$TCPDUMP" 2>/dev/null
  [ -n "$PPLAYS" ] && kill "$PPLAYS" 2>/dev/null
  rm -f "$SERVER_LOG" "$TCPDUMP_LOG"
}
trap cleanup EXIT INT TERM

do_help() {
  echo
  echo "Script pplay to replay smcap and capture it with tcpdump into pcap"
  echo
  echo "  $0 --smcap <source> --pcap <destination> [--verbose]"
  echo
  echo "  --pcap option can be omitted, file will be saved to /tmp/ "
  echo
  echo "    Result: replayed traffic pcap filename is the only stdout output for scripting purposes"
  echo "      Note: this tool must be able to listen on server port"
  echo "   Warning: this tool is a hack, please always verify its results, it's by far not perfect"
}

debuk() {
  if [ "$VERBOSE" = "1" ]; then
    echo "$1 $2 $3 $4"
  fi
}

errit() {
  echo "$1 $2 $3 $4" > /dev/stderr
}

while [ $# -gt 0 ];
do
  case $1 in
    --verbose|-v)
      VERBOSE=1;;

    --smcap)
      shift
      FNM="$1";;

    --pcap)
      shift
      OUTPUT_FILE="$1";;

    --help|-h|*)
      do_help
      exit;;
  esac
  shift
done

if [ "$FNM" = "" ]; then
  do_help
  exit 255
fi

if [ ! -f "$FNM" ]; then
  errit "smcap file doesn't exist"
  exit 1
fi

if [ "$OUTPUT_FILE" = "" ]; then
  OFILE=$(basename "$FNM" | sed -e "s/.smcap/.pcap/")
  OUTPUT_FILE="${OPATH}${OFILE}"
fi

if [ -f "$OUTPUT_FILE" ]; then
  errit "pcap file '$OUTPUT_FILE' already exists"
  exit 2
fi


do_run() {
    echo "output file: $OUTPUT_FILE"

    PPORT=$("${PROG}" --smcap "$FNM" --smprint dport 2>&1 | awk '/^[0-9]+$/ { port=$0 } END { print port }')
    if [ -z "$PPORT" ]; then
      errit "cannot detect destination port"
      return 3
    fi
    echo "Detected destination port: $PPORT"


    # detect colliding ports:
    RGX=$(netstat -nap | grep 'LISTEN ' | grep '\(0.0.0.0\|127.0.0.2\):[0-9]\+' | awk '{ print $4 }' | sed -e 's/::/0/g' | awk -F: '{ print $2 }' | sort -n | uniq | tr '\n' '|' | sed -e 's/|/\\|/g' | sed -e 's/|$//')

    PORT="$PPORT"
    while :; do

        if [ "$RGX" = "" ]; then
          break
        fi

        if echo "$PORT" | grep -Eq "^(${RGX})$"
        then
            echo "port $PORT is in collision with already opened port"
            INC=$(od -An -N2 -tu2 /dev/urandom | tr -d ' ')
            PORT=$((1024 + INC % 64512))
        else
            echo "using destination port '$PORT'"
            break
        fi
    done

    # to zeroize $?
    echo
    "${PROG}" --server 127.0.0.2:"$PORT" --smcap "$FNM" --auto 0.1 --exitoneot --nostdin --die-after 5 >"$SERVER_LOG" 2>&1 &

    PPLAYS=$!
    PPLAYS_RET=$?
    debuk "PPLAY SERVER RET" $PPLAYS_RET
    debuk "PPLAY SERVER PID $PPLAYS"

    sleep 0.5

    tcpdump -i lo -n 'host 127.0.0.2' -s 20000 -w "$OUTPUT_FILE" -U >"$TCPDUMP_LOG" 2>&1 &
    TCPDUMP=$!
    debuk "TCPDUMP PID $TCPDUMP"

    sleep 2;

    ${PROG} --client 127.0.0.2:"$PORT"  --smcap "$FNM"  --auto 0.1 --exitoneot --nostdin --die-after 5 2>&1 | awk '{ print "client > ",$0}'
    # wait for it to finish

    sleep 2;

    kill -INT "$TCPDUMP" 2>/dev/null
    wait "$TCPDUMP" 2>/dev/null
    TCPDUMP=''

    kill "$PPLAYS" 2>/dev/null
    wait "$PPLAYS" 2>/dev/null
    PPLAYS=''

    if [ "$VERBOSE" = "1" ]; then
      sed 's/^/server > /' "$SERVER_LOG"
      sed 's/^/tcpdump > /' "$TCPDUMP_LOG"
    fi
}

if [ "${VERBOSE}" = "1" ]; then
  do_run
else
  RUN_LOG=$(mktemp /tmp/smcap2pcap.XXXXXX)
  ( do_run ) >"$RUN_LOG" 2>&1
  rm -f "$RUN_LOG"
fi

echo "$OUTPUT_FILE"
