#!/bin/bash
# Written by Alex Simeonov, Barix AG, 06.11.2024
# this simple script monitors for "dead" ARP entries, and if it detects any
# it sets temporary static ARP entry pointing to device own MAC
# This is done to prevent Multicoder streams stuttering/skipping packets, if any
# of them fails to reach the destination (receiver/client device disconnected)
# NOTE: The problem appears only if Multicoder streams unicast to a device within its
# own network segment, then the ARP returns "incomplete"

ARP_MONITOR_NAME="arp_monitor"
LOCKFILE="/var/run/ARP_MONITOR_NAME".pid

function cleanup() {
    rm -f $pipe
    rm -f $LOCKFILE
}

# check for running instance/lockfile
if [ -e "$LOCKFILE" ]; then
  # lockfile exists
   if [ ! -r "$LOCKFILE" ]; then
      echo "Error: $LOCKFILE is not readable!"
      exit 1
   fi
   PID=`cat "$LOCKFILE"`
   kill -0 "$PID" 2>/dev/null
   if [ $? == 0 ]; then
      echo "Warning: instance of $ARP_MONITOR_NAME is already running, only resetting the ARP cache ..."
      ip neigh flush all > /dev/null
      exit 1
   fi
   # process that created lockfile is no longer running - delete lockfile
   rm -f "$LOCKFILE"
   if [ $? != 0 ]; then
      # error: failed to delete lockfile
      exit 1
   fi
fi

# create the lock file
echo $$ >"$LOCKFILE"
if [ $? != 0 ]; then
  # error: failed to create lockfile
   exit 1
fi

trap cleanup EXIT

# do the real work ...
# get my own MAC
my_mac=$(cat /sys/class/net/eth0/address)

# First, flush all ARP rules to start clean
# ARP entries will be recreated anyway
ip neigh flush all > /dev/null

# Loop through the ARP cache table twice per second, and "redirect" the incomplete ones to own MAC temporary (for about 10s)
while true; do
	ip_list=$(arp -e | grep -i incomplete)
	lines=$(echo "$ip_list" | wc -l)
	while IFS= read -r ip_line; do 
		ip=$(echo "$ip_line" | cut -d" " -f1)
		if [ "$ip" != "" ]; then                     
			echo "Creating temporary ARP entry for $ip=$my_mac"
			arp -s "$ip" "$my_mac" temp          
		fi
	done <<< "$ip_list"
	sleep 0.5
done

echo "ARP monitor  exiting ..."