#!/bin/sh
#
# Copyright (C) 2017 openwrt-ssr
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
. $IPKG_INSTROOT/etc/init.d/shadowsocksr
LOCK_FILE="/var/lock/ssr-monitor.lock"
[ -f "$LOCK_FILE" ] && exit 2
touch "$LOCK_FILE"

ps_list() {
	if busybox ps -w >/dev/null 2>&1; then
		busybox ps -w
	else
		busybox ps
	fi
}

match_proc_count() {
	local pattern="$1"
	ps_list | grep -E "$pattern" | grep -v grep | wc -l
}

redir_tcp_running() {
	local ssr_count
	local ipt_count
	ssr_count=$(match_proc_count 'ssr-retcp')
	ipt_count=$(ps_list | grep 'ipt2socks' | grep -v grep | grep -E ' -T( |$)| --tcp-only( |$)' | wc -l)
	echo $((ssr_count + ipt_count))
}

redir_udp_running() {
	local ssr_count
	local ipt_count
	ssr_count=$(match_proc_count 'ssr-reudp')
	ipt_count=$(ps_list | grep 'ipt2socks' | grep -v grep | grep -E ' -U( |$)| --udp-only( |$)' | wc -l)
	echo $((ssr_count + ipt_count))
}

kill_matched_procs() {
	local pattern="$1"
	ps_list | grep -E "$pattern" | grep -v grep | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
}

get_expected_threads() {
	local threads
	threads=$(uci_get_by_type global threads 0)
	if [ "$threads" = "0" ] || [ -z "$threads" ]; then
		threads=$(grep -c '^processor' /proc/cpuinfo 2>/dev/null)
	fi

	case "$threads" in
		''|*[!0-9]*)
			threads=1
			;;
	esac

	[ "$threads" -lt 1 ] && threads=1
	echo "$threads"
}

server_process_count=$1
redir_tcp_process=$2
redir_udp_process=$3
kcp_process=$4
local_process=$5
pdnsd_process=$6
if [ -z "$pdnsd_process" ]; then
	pdnsd_process=0
fi
i=0
GLOBAL_SERVER=$(uci_get_by_type global global_server)
GLOBAL_TYPE=$(uci_get_by_name $GLOBAL_SERVER type)
EXPECTED_THREADS=$(get_expected_threads)
server=$(uci_get_by_name $GLOBAL_SERVER server)
kcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port)
server_port=$(uci_get_by_name $GLOBAL_SERVER server_port)
password=$(uci_get_by_name $GLOBAL_SERVER kcp_password)
kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param)
[ "$password" != "" ] && password="--key "${password}

while [ "1" == "1" ]; do #死循环
	sleep 000030s
	#redir tcp
	if [ "$redir_tcp_process" -gt 0 ]; then
		icount=$(redir_tcp_running)
		local tcp_expected="$redir_tcp_process"
		if [ "$GLOBAL_TYPE" = "socks5" ]; then
			tcp_expected="$EXPECTED_THREADS"
		fi
		if [ "$icount" -lt "$tcp_expected" ]; then
			logger -t "$NAME" "ssrplus redir tcp error.restart!"
			echolog "ssrplus redir tcp error.restart!"
			/etc/init.d/shadowsocksr restart
			exit 0
		fi
	fi
	#redir udp
	if [ "$redir_udp_process" -gt 0 ]; then
		icount=$(redir_udp_running)
		local udp_expected="$redir_udp_process"
		if [ "$GLOBAL_TYPE" = "socks5" ]; then
			udp_expected="$EXPECTED_THREADS"
		fi
		if [ "$icount" -lt "$udp_expected" ]; then
			logger -t "$NAME" "ssrplus redir udp error.restart!"
			echolog "ssrplus redir udp error.restart!"
			/etc/init.d/shadowsocksr restart
			exit 0
		fi
	fi
	#server
	if [ "$server_process_count" -gt 0 ]; then
		icount=$(match_proc_count 'ssr-server|ss-server-|xray-server-')
		if [ "$icount" -lt "$server_process_count" ]; then #如果进程挂掉就重启它
			logger -t "$NAME" "ssrplus server error.restart!"
			echolog "ssrplus server error.restart!"
			kill_matched_procs 'ssr-server|ss-server-'
			/etc/init.d/shadowsocksr restart
			exit 0
		fi
	fi
	#kcptun
	if [ "$kcp_process" -gt 0 ]; then
		icount=$(ps_list | grep kcptun-client | grep -v grep | wc -l)
		if [ "$icount" -lt "$kcp_process" ]; then #如果进程挂掉就重启它
			logger -t "$NAME" "ssrplus kcptun error.restart!"
			echolog "ssrplus kcptun error.restart!"
			killall -q -9 kcptun-client
			(/usr/bin/kcptun-client -r $server:$kcp_port -l :$server_port $password $kcp_param &)
		fi
	fi
	#localsocks
	if [ "$local_process" -gt 0 ]; then
		icount=$(match_proc_count 'ssr-local|ss-local|tuic-local')
		if [ "$icount" -lt "$local_process" ]; then #如果进程挂掉就重启它
			logger -t "$NAME" "global socks server error.restart!"
			echolog "global socks server error.restart!"
			kill_matched_procs 'ssr-local|ss-local|tuic-local'
			/etc/init.d/shadowsocksr restart
			exit 0
		fi
	fi
	#dns2tcp
	if [ "$pdnsd_process" -eq 1 ]; then
		icount=$(ps_list | grep $TMP_BIN_PATH/dns2tcp | grep -v grep | wc -l)
		if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它
			logger -t "$NAME" "dns2tcp tunnel error.restart!"
			echolog "dns2tcp tunnel error.restart!"
			dnsserver=$(uci_get_by_type global tunnel_forward 8.8.4.4:53)
			kill -9 $(ps_list | grep $TMP_BIN_PATH/dns2tcp | grep -v grep | awk '{print $1}') >/dev/null 2>&1
			start_dns2tcp "$dnsserver"
		fi
	#mosdns
	elif [ "$pdnsd_process" -eq 4 ]; then
		icount=$(ps_list | grep $TMP_BIN_PATH/mosdns | grep -v grep | wc -l)
		if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它
			logger -t "$NAME" "mosdns tunnel error.restart!"
			echolog "mosdns tunnel error.restart!"
			dnsserver=$(uci_get_by_type global tunnel_forward 8.8.4.4:53)
			kill -9 $(ps_list | grep $TMP_BIN_PATH/mosdns | grep -v grep | awk '{print $1}') >/dev/null 2>&1
			ln_start_bin $(first_type mosdns) mosdns start -c /etc/mosdns/config.yaml
		fi
	#chinadns-ng(proxy)
	elif [ "$pdnsd_process" -eq 6 ]; then
		icount=$(ps_list | grep -e ssrplus-dns -e "chinadns-ng -b 127.0.0.1 -l $tmp_dns_port" | grep -v grep | wc -l)
		if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它
			logger -t "$NAME" "chinadns-ng $dnsserver tunnel error.restart!"
			echolog "chinadns-ng $dnsserver tunnel error.restart!"
			dnsserver=$(uci_get_by_type global chinadns_ng_tunnel_forward 8.8.4.4:53)
			kill -9 $(ps_list | grep "chinadns-ng -b 127.0.0.1 -l $tmp_dns_port" | grep -v grep | awk '{print $1}') >/dev/null 2>&1
			local chinadns_ng_proto="$(uci_get_by_type global chinadns_ng_proto)"
			local chinadns_ng_dns=""
			IFS=','
			for chinadns_ng_server in $dnsserver; do
				local chinadns_ng_ip="${chinadns_ng_server%%:*}"
				local chinadns_ng_port="${chinadns_ng_server##*:}"
				[ "$chinadns_ng_ip" = "$chinadns_ng_port" ] && chinadns_ng_port="53"
				chinadns_ng_tls_port="853"
				case "$chinadns_ng_proto" in
					"none")
						chinadns_ng_server="${chinadns_ng_ip}#${chinadns_ng_port}"
						;;
					"tls")
						chinadns_ng_server="${chinadns_ng_proto}://${chinadns_ng_ip}#${chinadns_ng_tls_port}"
						;;
					*)
						chinadns_ng_server="${chinadns_ng_proto}://${chinadns_ng_ip}#${chinadns_ng_port}"
						;;
				esac
					chinadns_ng_dns="${chinadns_ng_dns} -t ${chinadns_ng_server}"
			done
			unset IFS
			dnsserver="$chinadns_ng_dns"
			ln_start_bin $(first_type chinadns-ng) chinadns-ng -b 127.0.0.1 -l $tmp_dns_port -l $dns_port -p 3 -d gfw $dnsserver -N --filter-qtype 64,65 -f -r --cache 4096 --cache-stale 86400 --cache-refresh 20
		fi
	#built-in dns
	elif [ "$pdnsd_process" -eq 7 ]; then
		if ! is_builtin_dns_active; then
			logger -t "$NAME" "builtin dns error.restart!"
			echolog "builtin dns error.restart!"
			/etc/init.d/shadowsocksr restart
			exit 0
		fi
	fi
	#chinadns-ng(china)
	if [ "$(uci -q get "dhcp.@dnsmasq[0]._unused_ssrp_changed")" = "1" ]; then
		icount=$(ps_list | grep $TMP_BIN_PATH/chinadns-ng | grep -v grep | wc -l)
		if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它
			logger -t "$NAME" "chinadns-ng tunnel error.restart!"
			echolog "chinadns-ng tunnel error.restart!"
			chinadns=$(uci_get_by_type global chinadns_forward)
			wandns="$(ifstatus wan | jsonfilter -e '@["dns-server"][0]' || echo "119.29.29.29")"
			case "$chinadns" in
			"wan") chinadns="$wandns" ;;
			""|"wan_114") chinadns="$wandns,114.114.114.114" ;;
			esac
			kill -9 $(ps_list | grep $TMP_BIN_PATH/chinadns-ng | grep -v grep | awk '{print $1}') >/dev/null 2>&1
			ln_start_bin $(first_type chinadns-ng) chinadns-ng -l $china_dns_port -4 china -p 3 -c ${chinadns/:/#} -t 127.0.0.1#$dns_port -N -f -r
		fi
	fi
done
