#!/bin/bash

# Copyright (C) 2017-2018 X2Go Project - https://wiki.x2go.org
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

# Get first free port.
# Takes the current host name, a command for ss, the port type,
# a start and an end port as parameters.
# If an ss command is not given, a default of "ss" is assumed.
# If the port type is not given, a default of "lowlevel" is assumed.
# If the start port is not given, a default of 1 is assumed.
# If the end port is not given, a default of 65535 is assumed.
# Valid values for the port type are "lowlevel" and "display".
# Prints the first free port value on success, or the initial start
# port number on failure.
# Returns 0 on success or non-0 on failure.
typeset current_host_name="${1}"
typeset ss="${2:-"ss"}"
typeset type="${3:-"lowlevel"}"
typeset start="${4:-"1"}"
typeset end="${5:-"65535"}"

# Check parameter sanity.
typeset empty_regex='^[[:space:]]*$'
if [[ -z "${current_host_name}" ]] || [[ "${current_host_name}" =~ ${empty_regex} ]] || [[ "${current_host_name}" = '(none)' ]] || [[ "${current_host_name}" = 'localhost' ]]; then
	exit '2'
fi

if [[ -z "${ss}" ]] || [[ "${ss}" =~ ${empty_regex} ]]; then
	exit '3'
fi
typeset -i start_i="${start}"
typeset -i end_i="${end}"
if [[ -z "${start}" ]] || [[ "${start}" != "${start_i}" ]] || [[ "${start}" -ne "${start_i}" ]] || [[ "${start_i}" -lt '0' ]] || [[ "${start_i}" -gt '65535' ]]; then
	exit '4'
fi
if [[ -z "${end}" ]] || [[ "${end}" != "${end_i}" ]] || [[ "${end}" -ne "${end_i}" ]] || [[ "${end_i}" -lt "${start_i}" ]] || [[ "${end_i}" -gt '65535' ]]; then
	exit '5'
fi
[[ "${type}" != 'lowlevel' ]] && [[ "${type}" != 'display' ]] && exit '6'


typeset x2go_lib_path="$(x2gopath 'libexec')"
typeset X2GO_INTERNAL_SOURCE='1'
# Make shellcheck happy.
: "${X2GO_INTERNAL_SOURCE}"
. "${x2go_lib_path}/x2gocheckport"
unset X2GO_INTERNAL_SOURCE


typeset -i ret_port="${start}"
typeset -i ret='1'
typeset -i work_port='0'
typeset -i stop_port='65535'
[[ "${type}" = 'display' ]] && stop_port="$((stop_port - 6000))"
# Find the next free port number.
for ((work_port = start; i <= stop_port; ++work_port)); do
	typeset -i i='0'
	typeset -i value_found='0'

	if [[ "${type}" = 'display' ]]; then
		check_display_port "${current_host_name}" "${ss}" "${work_port}" || value_found='1'
	else
		check_x2go_port "${current_host_name}" "${work_port}" || value_found='1'

		if [[ "${value_found}" -eq '0' ]]; then
			check_system_port "${ss}" "${work_port}" || value_found='1'
		fi
	fi

	# Port number taken? Continue with the next one.
	[[ "${value_found}" -ne '0' ]] && continue

	# Searched and got nothing? Great, grab that port number!
	ret_port="${work_port}"
	ret='0'
	break
done

# At this point, ${ret} and ${ret_port} should be set up correctly.
# Either to the first free port value if one has been found (and ${ret}
# to zero) or to the start port value (and ${ret} to one.)
printf '%d\n' "${ret_port}"
exit "${ret}"
