#!/bin/bash
#
# (C) 2017-23 - ntop.org
#

# Default values
DEFAULT_MAX_RTT_MS=5000
DEFAULT_NUM_ATTEMPTS=5 # Number of pings for each test, to compute packet loss
DEFAULT_LOSS_THRESH=100 # Packet loss threshold to set the gateway down

ITERATION_INTERVAL=5
PINGS_INTERVAL=1

POISON=0

_term() {
    POISON=1
}

trap _term SIGTERM

_V=0
function log () {
  if [[ $_V -eq 1 ]]; then
    echo "$@"
  fi
}

# Main loop
while :; do
  if [[ "${POISON}" -eq "1" ]]; then
    break
  fi

  gateway_name=
  gateway_info=

  packet_loss_regex="([0-9]+\.?[0-9]*)% packet loss"
  rtt_avg_regex="rtt min/avg/max/mdev = ([0-9.]+)/([0-9]+)"

  # For all gateways in ntopng.gw_status.gateways
  while read -r line; do

    # Read gateway name and info
    if [[ -z "$gateway_name" ]]; then
      gateway_name="$line"
    else
      gateway_info="$line"

      #log "Gateway $gateway_name info: $gateway_info"

      IFS='|' read -r -a gateway_info <<< "$gateway_info"

      iface=${gateway_info[0]}
      gateway_ip=${gateway_info[1]}
      marker=${gateway_info[2]}
      ping_address=${gateway_info[3]}
      max_rtt_ms=${gateway_info[4]}
      loss_thresh=${gateway_info[5]}
      num_attempts=${gateway_info[6]}

      # RTT
      if [ -z "$max_rtt_ms" ]; then
        # Set default
        max_rtt_ms=$DEFAULT_MAX_RTT_MS
      fi
      max_rtt_sec=$(expr ${max_rtt_ms} / 1000)
      max_rtt_mod=$(expr ${max_rtt_ms} % 1000)
      if [[ "$max_rtt_mod" -gt "0" ]]; then
        max_rtt_sec=$(expr ${max_rtt_sec} + 1)
      fi
      if [[ "$max_rtt_sec" -eq "0" ]]; then
        max_rtt_sec=1
      fi

      # Number of attempts
      if [ -z "$num_attempts" ]; then
        # Set default
        num_attempts=$DEFAULT_NUM_ATTEMPTS
      fi
      if [[ "$num_attempts" -eq "0" ]]; then
        # Set min
        num_attempts=1
      fi

      # Loss Threshold
      if [ -z "$loss_thresh" ]; then
        # Set default
        loss_thresh=$DEFAULT_LOSS_THRESH
      fi
      if [[ "$loss_thresh" -eq "0" ]]; then
        loss_thresh=$(expr 100 / ${num_attempts})
      fi

      all_ping_deadline=$(expr ${num_attempts} \* ${max_rtt_sec})

      log "Testing $gateway_name ($gateway_ip) - pinging $ping_address via $iface marker $marker for $num_attempts times with a timeout of $max_rtt_sec sec ($all_ping_deadline total) and a threshold of $loss_thresh% ..."

      # Run ping test
      res="`ping -c $num_attempts -i $PINGS_INTERVAL -I $iface -n -q -W $max_rtt_sec -w $all_ping_deadline -m $marker $ping_address`"

      if [[ $res =~ $packet_loss_regex ]]; then
        loss_percentage=${BASH_REMATCH[1]}
        update_status=0
        new_status_up=1

	# Check packet loss
        if [[ ! -z $loss_percentage ]]; then

          #log "Checking Loss $loss_percentage (actual) < $loss_thresh (threshold)"

	  # Note: using bc to handle floats
          if [ 1 -eq "$(echo "${loss_percentage} >= ${loss_thresh}" | bc)" ]; then
            update_status=1
            new_status_up=0
	  else
            update_status=1
          fi
        fi

	# If packet loss ok, check RTT
        if [[ $new_status_up -eq 1 && $res =~ $rtt_avg_regex ]]; then
          rtt_average_ms=${BASH_REMATCH[2]}

          #log "Checking RTT $max_rtt_ms (actual) <= $rtt_average_ms (threshold)"

          if [[ "$rtt_average_ms" -gt "$max_rtt_ms" ]]; then
            update_status=1
            new_status_up=0
          fi
        fi

        # Update gateway status in ntopng.gw_status.status
        if [[ $update_status -eq 1 ]]; then
          [[ $new_status_up -eq 1 ]] && new_status_label="up" || new_status_label="down"
          log "$gateway_name is $new_status_label [${loss_percentage}% packet loss][$rtt_average_ms ms RTT]"
          redis-cli hset ntopng.gw_status.status $gateway_name "${new_status_label}|${marker}" >/dev/null
        fi
      fi
      gateway_name=
    fi
  done < <(redis-cli hgetall ntopng.gw_status.gateways)

  sleep $ITERATION_INTERVAL
done
