#!/bin/sh
# Copyright (C) 2024 iopsys Software Solutions AB
# Author: Suvendhu Hansa <suvendhu.hansa@iopsys.eu>

. /usr/share/libubox/jshn.sh

ROOT="$(dirname "${0}")"
. "${ROOT}"/bbf_api

UPLOAD_TIMEOUT=1800

packet_capture_error() {
	json_init
	json_add_string "Status" "$1"
	json_add_string "FileLocation" ""
	json_add_string "StartTime" "0"
	json_add_string "EndTime" "0"
	json_add_string "Count" "0"
	json_dump

	[ "$2" = "both_proto" ] && {
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.DiagnosticState="$1"
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.FileLocation=""
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.StartTime=0
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.EndTime=0
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.Count=0
		$UCI_COMMIT_BBF_DMMAP
	}
}

packet_capture_launch() {
	input="$1"
	intf=""
	filename=$(mktemp /tmp/capture.XXXXXXX)

	# Delete if any local capture file exist
	find / -name "packetcapture.pcap" -exec rm {} \;

	json_load "${input}"

	json_get_var interface interface
	json_get_var format format
	json_get_var duration duration
	json_get_var packet_count packet_count
	json_get_var file_target file_target
	json_get_var expression expression
	json_get_var username username
	json_get_var password password
	json_get_var proto proto
	json_get_var cancel cancel

	[ "$proto" = "both_proto" ] && {
		old_pid=$(cat /tmp/packetcapture_pid)

		[ -n "${old_pid}" ] && {
			cmd=$(cat /proc/$old_pid/cmdline)
		}

		if [[ "${cmd}" = *packetcapture* ]]; then
			kill -9 ${old_pid}
		fi

		if [ "${cancel}" -eq "1" ]; then
			json_init
			json_add_string "Status" "None"
			json_add_string "FileLocation" ""
			json_add_string "StartTime" "0"
			json_add_string "EndTime" "0"
			json_add_string "Count" "0"
			json_dump

			$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.DiagnosticState="None"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.FileLocation=""
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.StartTime=0
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.EndTime=0
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.Count=0
			$UCI_COMMIT_BBF_DMMAP

			return
		else
			echo $$ > /tmp/packetcapture_pid
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.DiagnosticState="Requested_running"
			$UCI_COMMIT_BBF_DMMAP
		fi
	}

	if [ -n "${format}" ] && [ "${format}" != "libpcap" ]; then
		# Error
		packet_capture_error "Error_Internal" "${proto}"
		return
	fi

	if [ -z "${file_target}" ]; then
		# Error
		packet_capture_error "Error_Internal" "${proto}"
		return
	fi

	if [ -n "${interface}" ]; then
		intf=$(ifstatus "${interface}" | jsonfilter -e '$.l3_device')

		if [ -z "${intf}" ]; then
			# Error
			packet_capture_error "Error_Internal" "${proto}"
			return
		fi
	fi

	cmd="timeout ${duration} tcpdump -w ${filename}"

	if [ -n "${intf}" ]; then
		cmd="${cmd} -i ${intf}"
	fi

	if [ "${packet_count}" -ne 0 ]; then
		cmd="${cmd} -c ${packet_count}"
	fi

	if [ -n "${expression}" ]; then
		cmd="${cmd} \"${expression}\""
	fi

	time_start=$(date +"%s")
	output=$(eval ${cmd} 2>&1 | grep "packets captured")
	res="$?"
	time_stop=$(date +"%s")

	if [ "${res}" -ne 0 ]; then
		# Error
		packet_capture_error "Error_Internal" "${proto}"
		return
	fi

	pkt_count=$(echo $output | cut -d' ' -f 1)

	if [[ "${file_target}" == "file://"* ]]; then
		# Local file
		file_target=$(realpath "${file_target:6}/packetcapture.pcap")
		if [ -z "${file_target}" ]; then
			# Invalid local path Error
			rm -rf "${filename}"
			res=1
		else
			# Copy file to destination
			mv "${filename}" "${file_target}"
			res="$?"
		fi
	else
		# Remote file
		opt=""
		if [ -n "${username}" ] && [ -n "${password}" ]; then
			opt="--user ${username}:${password}"
		fi

		file_target="${file_target}/packetcapture.pcap"
		opt="${opt} --upload-file ${filename}"
		eval curl --fail --silent "${opt}" --max-time ${UPLOAD_TIMEOUT} "${file_target}"
		res="$?"
		rm -rf "${filename}"
	fi

	if [ "$res" -ne 0 ]; then
		# Error
		packet_capture_error "Error_Internal" "${proto}"
		return
	else
		json_init
		json_add_string "Status" "Complete"
		json_add_string "FileLocation" "${file_target}"
		json_add_string "StartTime" "${time_start}"
		json_add_string "EndTime" "${time_stop}"
		json_add_string "Count" "${pkt_count}"
		json_dump

		[ "${proto}" = "both_proto" ] && {
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.DiagnosticState="Complete"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.FileLocation="${file_target}"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.StartTime="${time_start}"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.EndTime="${time_stop}"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.packetcapture.Count="${pkt_count}"
			$UCI_COMMIT_BBF_DMMAP
		}
	fi
}

if [ -n "$1" ]; then
	packet_capture_launch "$1"
else
	packet_capture_error "Error_Internal"
fi
