Wrapping Server Applications

Wrapping Server Applications

On occasion, a server administrator may wish to configure Centova Cast to run a "wrapper" application when launching the streaming server, instead of directly launching SHOUTcast DNAS or IceCast. This may be useful when running certain proxy applications, advertising software, or similar, which needs to be stopped and started in tandem with the server software.

In most cases, Centova Cast's event scripts system will suffice for launching such applications, however in certain cases the application in question may expect to launch DNAS or IceCast itself. In these cases, a wrapper script such as below may be used to "proxy" all signals and PID management between the third-party application and Centova Cast.

A Sample Wrapper Script

This wrapper script serves as an example of how to force Centova Cast to control an application other than SHOUTcast DNAS (or IceCast) when performing start, stop, and reload actions from within Centova Cast.

Note that this script is provided as a courtesy only, and (as with any customization to Centova Cast) is unsupported by Centova Technologies.

##!/usr/bin/env bash
## =============================================================================
## Centova Cast - Copyright 2014, Centova Technologies
## Skeleton server application wrapper script
## =============================================================================
##
## This is a stub script into which you can add your code to control your
## third-party application.
##

## This function is invoked when the streaming server needs to be started;
## replace the commands below with whatever commands are needed to start
## your third-party application.
function start_server {

    # put your commands to start your application here; if you need
    # the account's username, it's available as $USERNAME

    # ...

    # set RESULT to 0 if the application started successfully, or 1 if
    # it failed to start
    RESULT=$?

    return $RESULT
}

## This function is invoked when the streaming server needs to be stopped;
## replace the commands below with whatever commands are needed to stop
## your third-party application.
function stop_server {

    # put your commands to stop your application here

    return 0
}

## This function is invoked when the streaming server needs to close and
## reopen its log files; replace the commands below with whatever commands are
## needed to reload your third-party application.
function reload_server {

    # put your commands to reload your application here

    return 0
}

## This function is invoked to determine whether the streaming server is
## still running; replace the commands below with whatever commands are
## needed to check whether your third-party application is still
## running.
##
## Note that this is invoked every 2 seconds while monitoring the process,
## so for performance reasons it should NOT perform any heavy processing.
function check_server_running {

    # put your commands to check your third-party application state
    # here

    # set RUNNING to 1 if the application is still running, or 0 if
    # it is no longer running
    RUNNING=0

    return $RUNNING
}

## Everything below is wrapper code and can be left alone.

function stop_and_exit {
    stop_server
    exit 0
}

## trap signals
trap stop_and_exit INT TERM EXIT
trap reload_server HUP

while [ ! -z "$1" ]; do
    U=$1
    shift
done
U=${U#*\/}
USERNAME=${U%%\/*}

start_server
[ $? -gt 0 ] && exit $?

while [ true ]; do
    check_server_running
    [ $? -gt 0 ] && break
    sleep 2
done

exit 0

Note that this script will NOT do anything useful on its own. To make it work for your particular scenario, you MUST have at least some familiarity with bash scripting to make the changes noted in the script comments.

Implementing the Wrapper Script

To implement a wrapper script on your server, save the example script above as (for example) /usr/local/centovacast/bin/wrapper.sh. (Technically you can use any path or name, as long as filesystem permissions are observed.)

Next, make any changes that are necessary to launch your application correctly and obtain the PID of the streaming server.

Next, run:

chmod 0775 /usr/local/centovacast/bin/wrapper.sh

Finally, edit /usr/local/centovacast/etc/cc-control.conf and replace the path to SHOUTcast DNAS (or IceCast) with the path to the wrapper script. For example, if you want the wrapper script to be executed in place of SHOUTcast DNAS v2, find the line that begins with SHOUTCAST2_BIN= and replace it with:

SHOUTCAST2_BIN=/usr/local/centovacast/bin/wrapper.sh

This change takes effect immediately, and the next time any SHOUTcast DNAS v2 streams are stopped, started, or reloaded, the action will be performed through the wrapper script.

Practical Example: Controlling Apache

This script implements a simple wrapper which lets Centova Cast control the Apache web server instead of SHOUTcast DNAS. In more general terms, it's an example of wrapping an application that is controlled via an init script, or another short-lived control process.

##!/usr/bin/env bash
## =============================================================================
## Centova Cast - Copyright 2014, Centova Technologies
## Example application wrapper script to control Apache
## =============================================================================
##
## This script shows how to implement a wrapper for a third-party application
## that is controlled via an init script (or any other process management tool
## that takes separate start and stop commands).
##
## This (mostly useless) example demonstrates how to start or stop the Apache
## webserver when a user starts or stops his stream.
##

## This function is invoked when the streaming server needs to be started;
## replace the commands below with whatever commands are needed to start
## your third-party application.
function start_server {

    # start Apache via its init script; the 'ccuser' account would of
    # course need to be in /etc/sudoers for this to work
    sudo /etc/init.d/apache2 start

    # set RESULT to 0 if the application started successfully, or 1 if
    # it failed to start
    RESULT=$?

    return $RESULT
}

## This function is invoked when the streaming server needs to be stopped;
## replace the commands below with whatever commands are needed to stop
## your third-party application.
function stop_server {

    # stop Apache via its init script
    sudo /etc/init.d/apache2 stop

}

## This function is invoked when the streaming server needs to close and
## reopen its log files; replace the commands below with whatever commands are
## needed to reload your third-party application.
function reload_server {

    # reload Apache via its init script
    sudo /etc/init.d/apache2 force-reload

}

## This function is invoked to determine whether the streaming server is
## still running; replace the commands below with whatever commands are
## needed to check whether your third-party application is still
## running.
##
## Note that this is invoked every 2 seconds while monitoring the process,
## so for performance reasons it should NOT perform any heavy processing.
function check_server_running {

    # check Apache's status via its init script; the init script will
    # return an exit code of 0 if it's running, or 1 if it's not
    sudo /etc/init.d/apache2 status

    if [ $? -eq 0 ]; then
     RUNNING=1
    else
     RUNNING=0
    fi

    return $RUNNING
}

## Everything below is wrapper code and can be left alone.

function stop_and_exit {
    stop_server
    exit 0
}

## trap signals
trap stop_and_exit INT TERM EXIT
trap reload_server HUP

while [ ! -z "$1" ]; do
    U=$1
    shift
done
U=${U#*\/}
USERNAME=${U%%\/*}

start_server
[ $? -gt 0 ] && exit $?

while [ true ]; do
    check_server_running
    [ $? -gt 0 ] && break
    sleep 2
done

exit 0

Practical Example: Indirectly Controlling DNAS2

This script implements yet another simple wrapper which lets Centova Cast indirectly manage a SHOUTcast DNAS v2 process. In more general terms, it's an example of wrapping a long-lived process from an application which daemonizes and runs in the background after starting up.

##!/usr/bin/env bash
## =============================================================================
## Centova Cast - Copyright 2014, Centova Technologies
## Example application wrapper script to indirectly control DNAS2
## =============================================================================
##
## This script shows how to implement a wrapper for a third-party application
## that daemonizes itself and executes the streaming server as a subprocess
## which it then manages.
##
## This (mostly useless) example demonstrates running SHOUTcast DNAS v2
## as if it were in itself a third-party application.
##

## This function is invoked when the streaming server needs to be started;
## replace the commands below with whatever commands are needed to start
## your third-party application.
function start_server {

    # start DNAS v2 by changing to the virtual host directory and launching
    # the sc_serv process
    VHOSTDIR=/usr/local/centovacast/var/vhosts/$USERNAME
    [ ! -d $VHOSTDIR ] && echo "$VHOSTDIR does not exist" && return 1
    cd $VHOSTDIR
    /usr/local/centovacast/shoutcast22/sc_serv etc/server.conf

    # since, in this example, our process is going to continue running in the
    # background, we need to make note of its PID here so we can control
    # it later
    SERVERPID=$!

    # set RESULT to 0 if the application started successfully, or 1 if
    # it failed to start
    RESULT=$?

    return $RESULT
}

## This function is invoked when the streaming server needs to be stopped;
## replace the commands below with whatever commands are needed to stop
## your third-party application.
function stop_server {

    # we made note of the DNAS2 PID in start_server, and can now simply
    # send SIGTERM to that PID
    [ ! -z "$SERVERPID" -a -d /proc/$SERVERPID ] && kill $SERVERPID

}

## This function is invoked when the streaming server needs to close and
## reopen its log files; replace the commands below with whatever commands are
## needed to reload your third-party application.
function reload_server {

    # we made note of the DNAS2 PID in start_server, and can now simply
    # send SIGHUP to that PID
    kill -HUP $SERVERPID

}

## This function is invoked to determine whether the streaming server is
## still running; replace the commands below with whatever commands are
## needed to check whether your third-party application is still
## running.
##
## Note that this is invoked every 2 seconds while monitoring the process,
## so for performance reasons it should NOT perform any heavy processing.
function check_server_running {

    # we made note of the DNAS2 PID in start_server, and every active PID
    # under Linux is found under /proc/<pid>, so we can simply test for
    # its existence to determine whether DNAS2 is still running
    if [ -d /proc/$SERVERPID ]; then
    RUNNING=1
    else
    RUNNING=0
    fi

    return $RUNNING
}

## Everything below is wrapper code and can be left alone.

function stop_and_exit {
    stop_server
    exit 0
}

## trap signals
trap stop_and_exit INT TERM EXIT
trap reload_server HUP

while [ ! -z "$1" ]; do
    U=$1
    shift
done
U=${U#*\/}
USERNAME=${U%%\/*}

start_server
[ $? -gt 0 ] && exit $?

while [ true ]; do
    check_server_running
    [ $? -gt 0 ] && break
    sleep 2
done

exit 0

Further development

These examples demonstrate a few common scenarios for third-party application management, however these are not by any means the only ways you can manage application processes. You could, for example, use curl or wget to control applications managed via a SOAP API.

If you're having trouble with a particular implementation, consult any systems administrator who is experienced with bash shell scripting for assistance.