#!/system/bin/sh
#
# start_adb_via_wifi.sh enable adb via WiFi using a fixed TCP port
#
#h# Usage:
#h#
#h#    start_adb_via_wifi.sh  [ --reset_port | --reset-port | -r ]
#h#
#h# Parameter:
#h#
#h#   --reset_port - disable and enable adb via WiFi 
#h#
#
# This script enables adb via WiFi using the script enable_wireless_adb.sh and starts socat to forward connections to a fixed TCP port to the port used by adb via WiFi.
# After the start of socat, start_adb_via_wifi.sh keeps running in the background to restart the socat binary if necessary (e.g. because the WiFi connection failed).
#
# To temporary disable the restart of socat, create the file 
#
#     /data/local/tmp/enable_wireless_adb/do_not_restart_socat
#
# To re-enable the restart of socat, delete this file. If socat is not running, the script start_adb_via_wifi.sh checks every n seconds wether this file exists.
# The default value for n is 4; to use a different value, write it it to the semaphore file, e.g. to wait 60 seconds between the checks use
#
#    echo 60 >/data/local/tmp/enable_wireless_adb/do_not_restart_socat
#
# 
# To disable the script complete, create the file
#
#    /data/local/tmp/enable_wireless_adb/do_not_start_socat
#
# If this file exists, the script start_adb_via_wifi.sh is terminated immediately. To restart the script, the phone must be restarted.
#
#
# The script to enable adb via WiFi, enable_wireless_adb.sh, does not add the WLAN BSSID to the adbd keystore. This must be done manually once for each WLAN in the confirmation dialog in the Android GUI.
# To enable adding the WLAN BSSID to the adbd keystore in the script, create the file
#
#   /data/local/tmp/enable_wireless_adb/add_wlan_bssid
#
# and either disable and enable adb via WiFi in the GUI manual or just reboot the phone.
#
# The default fixed port for the adb WiFi connections is 9999. To use another port either set the environment variable SOCAT_PORT before executing this script or store the port to use in the 
# file /data/local/tmp/enable_wireless_adb/adb_wifi_port
#
#
# History
#   03.05.2025 /bs
#     initial release
#     
#   07.05.2025 /bs
#     the script now updates the Module description in the Magisk Module list
#     the script now writes the TCP port currently used to the file /data/local/tmp/enable_wireless_adb/current_adb_wifi_port
#

# -----------------------------------------------------------------------------

# -----------------------------------------------------------------------------
# define constants
#
__TRUE=0
__FALSE=1

# -----------------------------------------------------------------------------
#

SCRIPT_NAME="${0##*/}"

SCRIPT_DIR="${0%/*}"

VERBOSE=${__FALSE}

MODULE_PROP="/data/adb/modules/enable_wireless_adb/module.prop"

SOCAT="${SCRIPT_DIR}/socat"

DEFAULT_SOCAT_PORT="9999"

SOCAT_OPTIONS=""

ENABLE_WIRELESS_ADB_SCRIPT="${SCRIPT_DIR}/enable_wireless_adb.sh"

DATA_DIR="/data/local/tmp/enable_wireless_adb"

SOCAT_PORT_FILE="${DATA_DIR}/adb_wifi_port"

CURRENT_SOCAT_PORT_FILE="${DATA_DIR}/current_adb_wifi_port"

DEFAULT_SLEEP_INTERVALL=4

DISABLE_SOCAT_AUTOSTART_SEMFILE="${DATA_DIR}/do_not_start_socat"

DISABLE_SOCAT_RESTART_SEMFILE="${DATA_DIR}/do_not_restart_socat"

ADD_WLAN_BSSID_SEMAPHOR_FILE="${DATA_DIR}/add_wlan_bssid"

NETSTAT="/system/bin/real_netstat" 
[ ! -x "${NETSTAT}" ] && NETSTAT="$( which netstat )"


# -----------------------------------------------------------------------------
# check for an already running process
#
SEMFILE="/tmp/${SCRIPT_NAME}.run"

if [ -r "${SEMFILE}" ] ; then

# ugly code ...
  if [[ " $* " == *\ -h\ * || " $* " == *\ --help\ * ]] ; then
 
    grep "^#h#" $0 | cut -c4-
    exit 0
  else
    echo "ERROR: This script is already running: The file \"${SEMFILE}\" already exists"
    
    RUNNING_PID="$( cat "${SEMFILE}" )"
    if [ "${RUNNING_PID}"x != ""x ] ; then
      RUNNING_PROCESS="$( ps -f -p ${RUNNING_PID} 2>/dev/null | grep -v "PID" )"
      if [ "${RUNNING_PROCESS}"x != ""x ] ; then
        echo "The running process is "
        echo "${RUNNING_PROCESS}"  
      else
        echo "Looks like this is an orphan file that can be deleted -- the process with the pid ${RUNNING_PID} is not running anymore."
      fi
    fi
    
    exit 255
  fi
else
  echo "$$" >"${SEMFILE}"
fi

# -----------------------------------------------------------------------------
# install a trap handler to delete the semaphor file at script end
#
function cleanup {
  [ -r "${SEMFILE}" ] && rm -f "${SEMFILE}"
}

trap 'cleanup' 0 


# -----------------------------------------------------------------------------
#
function LogMsg {
  echo "$*"
}

function LogInfo {
  LogMsg "INFO: $*"
}

function LogWarning {
  LogMsg "WARNING: $*"
}

function LogError {
  LogMsg "ERROR: $*"
}

function LogRotate {
  LOGROTATE_CUR_FILE=""
  LOGROTATE_i=0
  LOGROTATE_j=0
  
  while [ $# -ne 0 ] ; do
    LOGROTATE_CUR_FILE="$1"
    shift

    [ ! -r "${LOGROTATE_CUR_FILE}" ] && continue

    for LOGROTATE_i in 8 7 6 5 4 3 2 1 0 ; do
      let LOGROTATE_j=LOGROTATE_i+1
      [ -r "${LOGROTATE_CUR_FILE}.${LOGROTATE_i}" ] && mv "${LOGROTATE_CUR_FILE}.${LOGROTATE_i}" "${LOGROTATE_CUR_FILE}.${LOGROTATE_j}"
    done
    mv "${LOGROTATE_CUR_FILE}" "${LOGROTATE_CUR_FILE}.0"
  done
}


# ----------------------------------------------------------------------
# die
#
# function: print a message and end the script
#
# usage: die [script_exit_code] [message]
#
# the parameter "message" is optional; the script will add a leading "ERROR: "
# to the message if the script_exit_code is not zero
#
# returns: n/a
#
function die  {
  THISRC=$1
  [ $# -ne 0 ] && shift
  THISMSG="$*"

  if [ "${THISMSG}"x != ""x ] ; then
    if [ ${THISRC} != 0 ] ; then
      LogError "${THISMSG} (RC=${THISRC})" >&2
    else
      LogMsg "${THISMSG}"
    fi
  fi

  exit ${THISRC}
}

# ----------------------------------------------------------------------
# isNumber
#
# check if a value is an integer
#
# usage: isNumber testValue
#
# returns: ${__TRUE} - testValue is a number else not
#
function isNumber {

# this code does not work in the sh in Android
#  [[ $1 == +([0-9]) ]] && THISRC=${__TRUE} || THISRC=${__FALSE}

# old code:
  if [ "$1"x != ""x ] ; then
    TESTVAR="$(echo "$1" | sed 's/[0-9]*//g' )"
    [ "${TESTVAR}"x = ""x ] && return ${__TRUE} || return ${__FALSE}
  fi
  
  return ${__FALSE}
}

# -----------------------------------------------------------------------------
#
  /system/bin/tty -s 
  if [ $? -ne 0 ] ; then   

    [ "${START_ADB_VIA_WIFI_LOGFILE}"x = ""x ] && START_ADB_VIA_WIFI_LOGFILE="${DATA_DIR}/${SCRIPT_NAME}.log"

    LogRotate "${START_ADB_VIA_WIFI_LOGFILE}"

#  echo "Writing all messages to the log file ${START_ADB_VIA_WIFI_LOGFILE}"

    exec 1>"${START_ADB_VIA_WIFI_LOGFILE}" 2>&1
  fi
  
  if [ -r /data/local/tmp/trace ] ; then
    set -x
  fi


# ---------------------------------------------------------------------


# ---------------------------------------------------------------------
#

PRINT_USAGE=${__FALSE}

# reset the port used by adb ?
#
RESET_ADB_VIA_WIFI=${__FALSE}

while [ $# -ne 0 ] ; do

  CUR_PARAMETER="$1"
  shift
  
  case ${CUR_PARAMETER} in

    --help | -h )
      PRINT_USAGE=${__TRUE}
      ;;

    --verbose | -v )
      VERBOSE=${__TRUE}
      ;;

    --reset_port | --reset-port | -r )
      RESET_ADB_VIA_WIFI=${__TRUE}
      ;;

    * )
      LogMsg "ERROR: Invalid parameter found: ${CUR_PARAMETER}"
      exit 10
      ;;
  esac
done  

if [ ${PRINT_USAGE} = ${__TRUE} ] ; then

  grep "^#h#" $0 | cut -c4-
  
  if [ ${VERBOSE} = ${__TRUE} ] ; then
    grep "^#H#" $0 | cut -c4-
  fi
  
  exit 0

fi

# ---------------------------------------------------------------------
#
# check if root access is working
#
ROOT_ACCESS_OKAY=${__TRUE}

# the user running this script
#
CUR_USER="$( id -un )"

SU_PREFIX=""

if [ "${CUR_USER}"x != "root"x ] ; then
  LogMsg "Running as non-root user ( ${CUR_USER} )"
  CUR_OUTPUT="$( su - -c "id -un" 2>/dev/null )"
  if [ "${CUR_OUTPUT}"x != "root"x ] ; then
    ROOT_ACCESS_OKAY=${__FALSE}
  else
    SU_PREFIX="su - -c "      
  fi
fi

# -----------------------------------------------------------------------------
# get the fixed TCP port to be used for the adb WiFi connections
#
if [ "${SOCAT_PORT}"x = ""x ] ; then
  if [ -r "${SOCAT_PORT_FILE}" ] ; then
    LogMsg "Reading the port for the adb WiFi connections from the file \"${SOCAT_PORT_FILE}\" ..."
    SOCAT_PORT="$( grep -E -v "^#|^$" "${SOCAT_PORT_FILE}" | tail -1 | tr "\t" " " | cut -f1 -d " "  )"
    isNumber "${SOCAT_PORT}"
    if [ $? -eq ${__TRUE} ] ;then
      LogMsg "The port for the adb WiFi connections is now \"${SOCAT_PORT}\" "
    else
      LogMsg "ERROR: \"${SOCAT_PORT}\" is NOT a valid port number"
      SOCAT_PORT=""
    fi
  fi
fi

if [ "${SOCAT_PORT}"x = ""x ] ; then
  LogMsg "Using the default port \"${DEFAULT_SOCAT_PORT}\" for the adb WiFi connections"
  SOCAT_PORT="${DEFAULT_SOCAT_PORT}"
fi

# write the current TCP port used to the status file
#
echo "${SOCAT_PORT}">"${CURRENT_SOCAT_PORT_FILE}"

# -----------------------------------------------------------------------------

if [ ! -x "${ENABLE_WIRELESS_ADB_SCRIPT}" ] ; then
  die 100 "The script \"${ENABLE_WIRELESS_ADB_SCRIPT}\" does not exist or is not executable"
fi


if [ ! -x "${SOCAT}" ] ; then
  die 105 "The binary \"${SOCAT}\" does not exist or is not executable"
fi

# -----------------------------------------------------------------------------

# define the logfile to be used by the script enable_wireless_adb.log
#
export ENABLE_WIRELESS_ADB_LOGFILE="${DATA_DIR}/enable_wireless_adb.log"


while true ; do

  CUR_IP_ADDRESS="$(  ifconfig -a | grep "inet " | grep -v 127.0.0 | awk '{ print $2 }' | cut -f2 -d ":"  )"
  if [ "${CUR_IP_ADDRESS}"x = ""x ] ; then
    CUR_IP_ADDRESS="$( ip addr list | grep "inet " | grep -v 127.0.0 | awk '{ print $2 }' | cut -f1 -d "/" )"
  fi

  if [ "${CUR_IP_ADDRESS}"x != ""x ] ; then
    CURRENT_IP_MSG=", the IP address is ${CUR_IP_ADDRESS}"
  else
    CURRENT_IP_MSG=", no IP address found"
  fi

  
  LogMsg ""
  LogMsg " ---------------------------------------------------------------------------- "
  LogMsg ""


  if [ -r "${DISABLE_SOCAT_AUTOSTART_SEMFILE}" ] ; then
    die 0 "The socat autostart is disabled"
  fi

  if [ -r "${DISABLE_SOCAT_RESTART_SEMFILE}" ] ; then
    FORWARD_MSG="Port forwarding to port ${SOCAT_PORT} is disabled"
  else
    FORWARD_MSG="Port forwarding to port ${SOCAT_PORT} is enabled"  
  fi

  if [ -r  "${MODULE_PROP}" ] ; then
    LogMsg "Correcting the Module description in the file \"${MODULE_PROP}\" ..."
    sed -i -e "s/description=.*/description=Enable adb via WiFi and configure port forwarding to a fixed TCP port (${FORWARD_MSG}${CURRENT_IP_MSG})/g" "${MODULE_PROP}"
  fi
  
  if [ -r "${DISABLE_SOCAT_RESTART_SEMFILE}" ] ; then
    
    LogMsg "The restart of socat is disabled"
    SLEEP_INTERVALL="$( grep -E -v "^#|^$" "${DISABLE_SOCAT_RESTART_SEMFILE}" | tail -1 | tr "\t" " " | cut -f1 -d " " )"
    if ! isNumber ${SLEEP_INTERVALL} ; then
      SLEEP_INTERVALL=${DEFAULT_SLEEP_INTERVALL}
    fi
    LogMsg "Sleeping for ${SLEEP_INTERVALL} seconds now ..."
    sleep ${SLEEP_INTERVALL}
  else

#
# check if we already know the port used for adb via WiFi
#

    ADB_VIA_WIFI_ALREADY_ENABLED=${__FALSE}

    LogMsg "Checking for an existing adb via WiFi configuration ..."
    ADB_WLAN_PORT="$( ${ENABLE_WIRELESS_ADB_SCRIPT} --print_port )"
    if [ "${ADB_WLAN_PORT}"x != ""x ] ; then

#       TESTVAR="$( ${NETSTAT} -tnlp 2>/dev/null )"
#       TESTVAR="$( echo "${TESTVAR}" | tr "\t" " " )"
#       echo "${TESTVAR}" | grep ":${ADB_WLAN_PORT} " 

      ${NETSTAT} -tnlp 2>/dev/null | tr "\t" " " | grep ":${ADB_WLAN_PORT} " 
      if [ $? -eq 0 ] ; then
        LogMsg "Found a configured adb via WiFi configuration."
        if [ ${RESET_ADB_VIA_WIFI} != ${__TRUE} ] ; then
          ADB_VIA_WIFI_ALREADY_ENABLED=${__TRUE}
          LogMsg "Using the already configured port for adb via WiFi "
        fi
      fi
    fi
    
#
# enable adb via wireless
#
    if [ ${ADB_VIA_WIFI_ALREADY_ENABLED} != ${__TRUE} ] ; then

      SCRIPT_PARAMETER="--nostatus"

      if [ ${RESET_ADB_VIA_WIFI} = ${__TRUE} ] ; then
        LogMsg "Resetting the port used for adb via WiFi requested via parameter"
        SCRIPT_PARAMETER="${SCRIPT_PARAMETER} --reset_port"
      fi
      
      [ ! -r "${ADD_WLAN_BSSID_SEMAPHOR_FILE}" ] && SCRIPT_PARAMETER="${SCRIPT_PARAMETER} --ignore_BSSID"
    
      ${ENABLE_WIRELESS_ADB_SCRIPT} ${SCRIPT_PARAMETER}
    
#        
# read the port used for adb via wireless
#
      LogMsg "Retrieving the port used for adb via WiFi ...."

      ADB_WLAN_PORT="$( ${ENABLE_WIRELESS_ADB_SCRIPT} --print_port )"
    fi
    
    if   [ "${ADB_WLAN_PORT}"x = ""x ] ; then
      LogError "Can not get the port used for adb via wireless"
    else
      LogMsg "The port used for adb via WiFi is \"${ADB_WLAN_PORT}\" "

      LogMsg "Starting socat at $( date ) ...."
      START_SOCAT_CMD="${SOCAT} ${SOCAT_OPTIONS} TCP-LISTEN:${SOCAT_PORT},reuseaddr TCP:127.0.0.1:${ADB_WLAN_PORT},retry=0"

      set -f
      [[ $- == *x* ]] && TRACE_ACTIVE=${__TRUE} || TRACE_ACTIVE=${__FALSE}
      set +f
      set -x

#      echo "Executing \"${START_SOCAT_CMD}\" ...."
 
      ${START_SOCAT_CMD}
      THISRC=$?

      [ ${TRACE_ACTIVE} = ${__FALSE} ] && set +x
      
      LogMsg "socat ended with RC=${THISRC}"
    fi
  fi
done

exit 0

