#!/bin/bash
#
#       /etc/rc.d/init.d/nsc
#
#       The FreeSwitch Open Source Voice Platform
#
#  chkconfig: 345 89 14
#  description: Starts and stops the freeswitch server daemon
#  processname: freeswitch
#  config: /opt/freeswitch/conf/freeswitch.conf
#  pidfile: /opt/freeswitch/run/freeswitch.pid
#

# Source function library.
. /etc/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0

# Source auto-configure functions
[ -e /etc/init.d/functions-automagic ] && source /etc/init.d/functions-automagic
[ -e /etc/sysconfig/automagic ] && source /etc/sysconfig/automagic

# Source options file
if [ -f /etc/sysconfig/nsc ]; then
    . /etc/sysconfig/nsc
fi

# Source override options
if [ -f /etc/sysconfig/nsc.override ]; then
    . /etc/sysconfig/nsc.override
fi

if [[ -n "$ENABLE_VALGRIND" ]]; then
    PROG_NAME=valgrind
else
    PROG_NAME=nsc
fi

while IFS='=' read key value; do
    if [[ ${key,,} == 'product' ]]; then
        PRETTY_NAME="$value"
        break;
    fi
done <"/usr/local/nsc/conf/license/License.txt"

PRETTY_NAME=${PRETTY_NAME-NetBorder Session Controller}
MEMPRELOADER=${MEMPRELOADER-/usr/local/bin/malloc-preloader}
PID_FILE=${PID_FILE-/usr/local/nsc/run/freeswitch.pid}
FS_USER=${FS_USER-root}
FS_FILE=${FS_FILE-/usr/local/nsc/bin/nsc}
FS_HOME=${FS_HOME-/usr/local/nsc}
FS_LOG_CORE=${FS_HOME}/log/core.log
FS_LOG_FILE=/var/log/nsc/nsc.log
VG_LOG_DIR=/var/log/valgrind
LOCK_FILE=/var/lock/subsys/nsc
STOP_FILE=/var/lock/stop.nsc
RETVAL=0
VOCMAC=""
CLEAN_LOOP=30
RECOVER_LOOP=30

# <define any local shell functions used by the code that follows>

FS_TMPFS_ENABLE="YES"
FS_TMPFS_LOG_DIR=/var/log/nsc
FS_TMPFS_LOG_ARCHIVE=${FS_HOME}/log_archive
FS_TMPFS_LOG_ARCHIVE_LIMIT=10

FS_TMPFS_DATA_DIR=${FS_HOME}/data
FS_TMPFS_CDR_BASE=data/xml_cdr
FS_TMPFS_CDR_DIR=${FS_HOME}/${FS_TMPFS_CDR_BASE}

FS_TMPFS_SIZE_LIMIT=536870912 # 512 mb
FS_TMPFS_ARCHIVE_LIMIT=10

declare -A SERVICE_ENABLE_MAP=( [rtcpmon]=$NSC_RTCPMON_ENABLE [sipsecmon]=$NSC_SIPSECMON_ENABLE [mediamon]=$NSC_MEDIAMON_ENABLE )

cleanup_tmpfs_helper() {
    count=$FS_TMPFS_ARCHIVE_LIMIT

    while [ "$count" != "0" ]; do
        if ! read; then return 0; fi
        count=$(($count-1))
    done

    while read dir; do
        rm -rf "$FS_TMPFS_LOG_ARCHIVE/${dir}"
    done
}

cleanup_tmpfs() {
    find "$FS_TMPFS_LOG_ARCHIVE" -mindepth 1 -maxdepth 1 -type d -printf '%P\n' | \
        sort -rn | cleanup_tmpfs_helper
}

backup_tmpfs_helper() {
    tmstamp=`date '+%F.%H-%M-%S'`
    destdir="$FS_TMPFS_LOG_ARCHIVE/${tmstamp}"

    while read file; do
        filedir=`dirname "$file"`
        mkdir -p "${destdir}/${filedir}"
        cp -u "$FS_TMPFS_LOG_DIR/$file" "${destdir}/${file}"
    done
}

backup_tmpfs() {
    find "$FS_TMPFS_LOG_DIR" -name '*.log*' -printf '%P\n' | backup_tmpfs_helper

    cleanup_tmpfs
}

setup_tmpfs() {
    if [ ! -e "$FS_TMPFS_CDR_DIR" ]; then
        if [ ! -e "${FS_TMPFS_LOG_DIR}/xml_cdr" ]; then
            mkdir -p "$FS_TMPFS_CDR_DIR" && \
                chown webconfig:root "$FS_TMPFS_DATA_DIR" && chmod 0750 "$FS_TMPFS_DATA_DIR" && \
                chown webconfig:root "$FS_TMPFS_CDR_DIR"  && chmod 0750 "$FS_TMPFS_CDR_DIR"

        elif [ ! -h "${FS_TMPFS_LOG_DIR}/xml_cdr" ]; then
            mkdir -p "$FS_TMPFS_DATA_DIR" && \
                chown webconfig:root "$FS_TMPFS_DATA_DIR" && chmod 0750 "$FS_TMPFS_DATA_DIR" && \
                mv "${FS_TMPFS_LOG_DIR}/xml_cdr" "$FS_TMPFS_CDR_DIR"
        fi
    fi

    if [ ! -h log ] ; then
        ln -fs . log
    fi

    if [ ! -h xml_cdr ]; then
        ln -fs ../${FS_TMPFS_CDR_BASE} xml_cdr
    fi
}

enable_tmpfs() {
    if [ ! -e "$FS_TMPFS_LOG_DIR" ]; then
        mkdir -p "$FS_TMPFS_LOG_DIR"
    fi

    if [ ! -e "$FS_TMPFS_LOG_ARCHIVE" ]; then
        mkdir -p "$FS_TMPFS_LOG_ARCHIVE"
    fi

    backup_tmpfs

    if ! grep -q $FS_TMPFS_LOG_DIR /proc/mounts; then
        webuid=`awk -F: '/^webconfig:/ { print $3 }' /etc/passwd 2>/dev/null`
        mount -t tmpfs -o mode=0750,uid=$webuid,gid=0,size=$FS_TMPFS_SIZE_LIMIT none "$FS_TMPFS_LOG_DIR" || return 1

    fi

    [ ! -f "$FS_LOG_CORE" ] && touch "$FS_LOG_CORE"

    ln -sf "$FS_LOG_CORE" "/var/log/core-nsc.log"

    #(cd "$FS_TMPFS_LOG_DIR" && setup_tmpfs)
}

disable_tmpfs_helper() {
    if [ ! -h log ] ; then
        ln -fs . log
    fi
}

disable_tmpfs() {
    if ! grep -q $FS_TMPFS_LOG_DIR /proc/mounts; then
        return 0
    fi

    backup_tmpfs

    umount "$FS_TMPFS_LOG_DIR" || return 1

    (cd "$FS_TMPFS_LOG_DIR" && disable_tmpfs_helper)
}

enable_dnsmasq() {

    #check if dnsmasq already enabled
    DNSMASQ_STATUS=`grep 'nameserver 127.0.0.1' /etc/resolv.conf`

    if [ -z "$DNSMASQ_STATUS" ]; then
        awk -F' ' '{ if ($1 == "nameserver") { print > "/etc/resolv.dnsmasq.new" } else { print > "/etc/resolv.conf.new" } }' /etc/resolv.conf && \
            touch /etc/resolv.conf.new /etc/resolv.dnsmasq.new  && \
            echo 'nameserver 127.0.0.1' >> /etc/resolv.conf.new && \
            mv -f /etc/resolv.conf.new /etc/resolv.conf         && \
            mv -f /etc/resolv.dnsmasq.new /etc/resolv.dnsmasq
    fi

    service dnsmasq restart > /dev/null 2>&1
}

disable_dnsmasq() {
    #check if dnsmasq already enabled
    DNSMASQ_STATUS=`grep 'nameserver 127.0.0.1' /etc/resolv.conf`

    if [ ! -z "$DNSMASQ_STATUS" ]; then
        grep -v '^nameserver' /etc/resolv.conf > /etc/resolv.conf.new
        cat /etc/resolv.dnsmasq >> /etc/resolv.conf.new
        mv -f /etc/resolv.conf.new /etc/resolv.conf
    fi
}

dump_log_errors()
{
    cat "$FS_LOG_CORE" "$FS_LOG_FILE" 2>/dev/null | \
        grep '\[ALERT\|CRIT\|ERR\]' | \
            sed -e 's/\(.\+\)[.][0-9]+ \(\[[A-Z]+\]\) [^ ]\+ \(.\+\)/(\1) \2 \3/'
    echo
}

reload_service()
{
    service_name=$1
    if [ ${SERVICE_ENABLE_MAP[$service_name]}  = "true" ]
    then
        service $service_name status > /dev/null 2>&1
        # check if service is stopped.
        # $? = 0 means the service is running
        # $? = 3 means the service is stopped
        if [[ $? == 3 ]]
        then
           service $service_name start
        else
           service $service_name restart
        fi
    fi
}

start() {
    reload_service rtcpmon
    reload_service sipsecmon
    reload_service mediamon

    echo -n "Starting $PRETTY_NAME: "
    if [ -e $LOCK_FILE ]; then
        if [ -e $PID_FILE ] && [ -e /proc/`cat $PID_FILE` ]; then
            echo
            echo -n $"$PRETTY_NAME is already running.";
            failure $"$PRETTY_NAME is already running.";
            echo
            return 1
        fi
    fi

    if [ "$FS_TMPFS_ENABLE" != "YES" ]; then
        disable_tmpfs
    else
        enable_tmpfs || echo "WARNING: unable to enable tmpfs optimization"
    fi

    cd $FS_HOME

    # Make sure core file size is not limited
    ulimit -c unlimited

    if [[ -n "$ENABLE_VALGRIND" ]]; then
        [[ ! -e "$VG_LOG_DIR" ]] && mkdir -p "$VG_LOG_DIR"

        LAUNCHER=(valgrind
          --tool=memcheck
          --leak-check=full
          --leak-resolution=high
          --show-reachable=yes
          --xml=yes
          --xml-file="$VG_LOG_DIR/vg_log.xml")
        NSC_ARGS=(-vg -nonat)

        ${LAUNCHER[@]} $FS_FILE ${NSC_ARGS[@]} >/dev/null 2>&1 &
        echo -n $! >$PID_FILE  # write valgrind's pid to the pidfile ourselves
    else
        LAUNCHER=(daemon --user $FS_USER --pidfile $PID_FILE $MEMPRELOADER)
        NSC_ARGS=(-ncwait -nonat -nocal -rp)

        ${LAUNCHER[@]} $FS_FILE ${NSC_ARGS[@]} >/dev/null 2>&1
    fi

    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch $LOCK_FILE;
    echo

    if [ $RETVAL -ne 0 ]; then
        [ -f "$FS_LOG_CORE" -o -f "$FS_LOG_FILE" ] && dump_log_errors
    fi

    # Everything ok, so allow restarts from the core collector
    [ $RETVAL -eq 0 ] && rm -f $STOP_FILE

    return $RETVAL
}

stop() {
    echo -n "Stopping $PRETTY_NAME: "
    if [ ! -e $LOCK_FILE ]; then
        echo
        echo -n $"cannot stop $PRETTY_NAME: $PRETTY_NAME is not running."
        failure $"cannot stop $PRETTY_NAME: $PRETTY_NAME is not running."
        echo
        return
    fi

    # Process is now in stopped state
    touch $STOP_FILE

    cd $FS_HOME

    PIDNUM=$(<$PID_FILE)

    $FS_FILE -stop > /dev/null 2>&1
    RETVAL=$?
    if [ -n "$PIDNUM" -a -e "/proc/$PIDNUM" ]
    then
        if [ $RETVAL -ne 0 ]
        then
            echo -n $"stopping $PRETTY_NAME failed (ret=$RETVAL), sending term signal..."
            kill 15 $PIDNUM
            RETVAL=$?
        fi

        # wait for process to leave
        for ((i=0;i<30;++i)); do
            [ ! -e "/proc/$PIDNUM" ] && break
            sleep 1
        done

        if [ -e "/proc/$PIDNUM" ]
        then
            echo -n $"stopping $PRETTY_NAME failed (ret=$RETVAL), sending kill signal..."
            kill 9 $PIDNUM
            RETVAL=$?
        fi
    fi

    [ $RETVAL -eq 0 ] && success || failure
    echo
    [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE;

    #let us stop rtcpmon
    service rtcpmon stop
    #let us stop sipsecmon
    service sipsecmon stop
    #let us stop mediamon
    service mediamon stop

    if [ "$FS_TMPFS_ENABLE" = "YES" ]; then
        backup_tmpfs
    fi

    return $RETVAL
}

# arg 1: service name
forcestop() {

    service_pid=`pidof $1`
    if [[ ! -z "$service_pid" ]]; then
        if [[ ! -z $LOCK_FILE ]]; then
            rm -f "$LOCK_FILE"
        fi
        kill -9 $service_pid
        echo "service $PRETTY_NAME has been force stopped"
    else
        echo "service $PRETTY_NAME already stopped"
    fi

    if [ "$FS_TMPFS_ENABLE" = "YES" ]; then
        backup_tmpfs
    fi
}


# arg 1: service name
cleanup() {

    service_pid=`pidof $1`
    if [[ ! -z "$service_pid" ]]
    then
        echo "forcing service $PRETTY_NAME to stop before cleaning up."
        service $1 forcestop
    fi

    if [[ ! -z $LOCK_FILE ]]; then
        rm -f "$LOCK_FILE"
        echo "removed lock file $LOCK_FILE"
    fi

    if [ "$FS_TMPFS_ENABLE" = "YES" ]; then
        backup_tmpfs
    fi
}

# service1 service pid
showstats(){
    STATS=(`ps --no-headers -o pcpu,rss,etime $1`)
    echo "CPU Usage: ${STATS[0]} %, Memory Usage: ${STATS[1]} KB, Uptime: ${STATS[2]}"
}

# arg 1: service name
sngstatus() {

    service_pid=`pidof $1`
    if [[ ! -z "$service_pid" ]]; then
        if [[ -f "$LOCK_FILE" ]]; then
            echo "service $PRETTY_NAME is running"
        else
            echo "service $PRETTY_NAME is stopping, please wait."
        fi
        showstats $service_pid
        return 0
    else
        echo "service $PRETTY_NAME is stopped"
        return 3
    fi
}

silentstatus() {
    service_pid=`pidof $1`
    if [[ ! -z "$service_pid" ]]; then
        return 0
    else
        return 3
    fi
}

rhstatus() {
    sngstatus $PROG_NAME;
}

recover() {
    c=1
    stat=0
    while (( $c <= $RECOVER_LOOP )); do
        silentstatus $PROG_NAME
        stat=$?
        if (( stat == 3 )); then
            start
            break
        else
            sleep 1
            (( c++ ))
        fi
    done
}

voccleanup() {
    if [ -n "$EXTIF" ]; then

        for INTERFACE in $EXTIF; do

            MACWORD=$(ifconfig $INTERFACE | grep HWaddr)
            VOCMAC=$(awk -v MACSTR="$MACWORD" 'BEGIN {i=index(MACSTR, "HWaddr"); print substr(MACSTR, i+7, 17)}')

            [[ "$VOCMAC" != "02:19:23"* ]] && continue

            #let's wait for nsc stop and clean up vocallo
            c=1
            stat=0
            while (( $c <= $CLEAN_LOOP )); do
                silentstatus $PROG_NAME
                stat=$?
                if (( stat == 3 )); then
                    echo -n "Resetting Media Server:"
                    /usr/local/nsc/bin/sngtc_tool -dev $INTERFACE -reset
                    echo "                                    [  OK  ]"
                    break
                else
                    sleep 1
                    (( c++ ))
                fi
            done

            #if media server not stopped in 30 seconds, force to stop
            if (( $c > $CLEAN_LOOP )); then
                forcestop $PROG_NAME
                break
            fi

        done

    fi
}

case "$1" in
    start)
    if ! status -p $PID_FILE $PROG_NAME >/dev/null; then
        enable_dnsmasq
        start
    fi
    ;;
    stop)
    if status -p $PID_FILE $PROG_NAME >/dev/null; then
        stop
        disable_dnsmasq
    fi
    ;;
    status)
    sngstatus $PROG_NAME
    RETVAL=$?
    ;;
    cleanup)
    cleanup $PROG_NAME
    ;;
    forcestop)
    forcestop $PROG_NAME
    ;;
    restart)
    stop
    enable_dnsmasq
    start
    ;;
    recover)
    recover
    ;;
    condrestart)
    [ -f $PID_FILE ] && restart || :
    ;;
    *)
    echo "Usage: $PROG_NAME {start|stop|status|restart|forcestop|cleanup}"
    exit 1
    ;;
esac
exit $RETVAL
