#!/bin/bash

CLIENT_VM="client"
CLIENT_IP="10.6.6.10"
SERVER_VM="server"
SERVER_IP="10.6.6.20"
USER="ubuntu"
PASSWORD="ubuntu"

SIZE="10"
FILENAME="${SIZE}MB.file"

TCPDUMP_DURATION=3600
TCP_CC_COMBINATIONS=("reno reno" "reno bbr" "bbr reno" "bbr bbr")

if [ $# -eq 0 ]; then
    echo "Specify output directory for dumps. Ex. ./run_benchmarks dumps/profile1"
    exit
else
    OUTPUT_DIR="$1"
    echo "Using specified output directory: $OUTPUT_DIR"
fi

for cmd in sshpass tcpdump capinfos editcap bc; do
    if ! command -v $cmd &>/dev/null; then
        echo "Error: $cmd is not installed. Please install it first."
        exit 1
    fi
done

echo "Available network interfaces:"
interfaces=($(ip -o link show | awk -F': ' '{print $2}'))
PS3="Select interface number: "
select interface in "${interfaces[@]}"; do
    if [[ -n "$interface" ]]; then
        echo "Selected interface: $interface"
        break
    else
        echo "Invalid selection. Try again."
    fi
done

mkdir -p "$OUTPUT_DIR"

run_vm() {
    vm=$1
    cmd=$2
    sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no "$USER@$vm" "$cmd"
}

set_tcp_cc() {
    vm=$1
    cc=$2
    run_vm "$vm" "sudo sysctl -w net.ipv4.tcp_congestion_control=$cc"
}

run_benchmark() {
    protocol=$1
    client_cc=$2
    server_cc=$3
    suffix=$4

    if [[ "$suffix" == "tcp" ]]; then
        base_name="${protocol}_${client_cc}_${server_cc}"
    else
        base_name="${protocol}"
    fi

    pcap_file="${OUTPUT_DIR}/${base_name}_unsynced.pcap"
    pcap_file_synced="${OUTPUT_DIR}/${base_name}.pcap"

    case $protocol in
    http1)
        filter="tcp and port 80 and host ${CLIENT_IP} and host ${SERVER_IP}"
        ;;
    http2)
        filter="tcp and port 81 and host ${CLIENT_IP} and host ${SERVER_IP}"
        ;;
    http3)
        filter="udp and port 443 and host ${CLIENT_IP} and host ${SERVER_IP}"
        ;;
    tftp)
        filter="udp and host ${CLIENT_IP} and host ${SERVER_IP}"
        ;;
    esac

    echo "Starting $protocol capture with filter: $filter"

    timeout $TCPDUMP_DURATION \
        tcpdump -i "$interface" -w "$pcap_file" "$filter" \
        >/dev/null 2>&1 &
    tcpdump_pid=$!
    sleep 2

    case $protocol in
    http1)
        run_vm "$CLIENT_VM" "curl -s -o /dev/null 'http://$SERVER_VM:80/$FILENAME?client=$client_cc&server=$server_cc'"
        ;;
    http2)
        run_vm "$CLIENT_VM" "curl -s -o /dev/null --http2-prior-knowledge 'http://$SERVER_VM:81/$FILENAME?client=$client_cc&server=$server_cc'"
        ;;
    http3)
        run_vm "$CLIENT_VM" "./curl -s -o /dev/null --http3-only --insecure https://$SERVER_VM:443/$FILENAME"
        ;;
    tftp)
        run_vm "$CLIENT_VM" "rm -f $FILENAME; tftp $SERVER_VM -c get /var/www/$FILENAME"
        ;;
    esac

    sleep 4
    kill $tcpdump_pid 2>/dev/null
    wait $tcpdump_pid 2>/dev/null

    echo "Capture saved to $pcap_file"

    first_packet_time=$(capinfos -a -S "$pcap_file" 2>/dev/null | awk '/Earliest packet time/ {print $4}')
    time_shift=$(echo "-$first_packet_time" | bc -l)
    editcap -t "$time_shift" "$pcap_file" "$pcap_file_synced" >/dev/null 2>&1
    rm $pcap_file
    echo -e "Capture first packet time shifted to the beginning of epoch time, saved to $pcap_file_synced, old file removed"
}

for combination in "${TCP_CC_COMBINATIONS[@]}"; do
    read client_cc server_cc <<<"$combination"
    echo -e "\nRunning TCP benchmarks with ($client_cc/$server_cc) congestion control"

    set_tcp_cc "$CLIENT_VM" "$client_cc"
    set_tcp_cc "$SERVER_VM" "$server_cc"

    run_benchmark "http1" "$client_cc" "$server_cc" "tcp"
    run_benchmark "http2" "$client_cc" "$server_cc" "tcp"
done

echo -e "\nRunning UDP benchmarks"
run_benchmark "http3" "" "" "udp"
run_benchmark "tftp" "" "" "udp"

echo -e "\nAll benchmarks have been run, dumps have been stored in $OUTPUT_DIR"
mergecap -w $OUTPUT_DIR/merged.pcap "$OUTPUT_DIR"/*.pcap
echo -e "\nDumps have been merged: $OUTPUT_DIR/merged.pcap"
