// 
// 
// Copyright (C) 2004 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
// 
// Copyright (C) 2004 Pingtel Corp.
// Licensed to SIPfoundry under a Contributor Agreement.
// 
// $$
//////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES
// DEFINES
#define IMDB_BAD_FILE SIPX_TMPDIR "/imdb.bad"

// APPLICATION INCLUDES
#include "os/OsQueuedEvent.h"
#include "os/OsEventMsg.h"
#include "os/OsTimer.h"
#include "os/OsDateTime.h"
#include "os/OsFS.h"
#include "IMDBTaskMonitor.h"
#include "ImportTask.h"
#include "DisplayTask.h"
#include "KeepAliveTask.h"
#include "HeartBeatMonitor.h"

extern UtlBoolean gShutdownFlag;

IMDBTaskMonitor::IMDBTaskMonitor (
    const UtlString& rCommand,
    const UtlString& rArgument,
    const int& rMonitorSecs ) :
    mErrno(0),
    mMonitorSecs ( rMonitorSecs ),
    mCommandName ( rCommand ),
    mCommandEvent(),
    mCommandCompleted (FALSE)
{
    // Create the watchdog event/timer
    mpTimeoutEvent = new OsQueuedEvent( *getMessageQueue(), 0 ) ;

    //set subtype to signify user action
    mpTimeoutEvent->setUserData( USER_TIMEOUT_EVENT);
    mpWatchDogTimer = new OsTimer(*mpTimeoutEvent) ;

    // Finally construct the heartbeat thread that hits the IMDB
    mpIMDBWorkerTask = NULL;

    if ( rCommand.compareTo("heartbeat", UtlString::ignoreCase) == 0 )
    {
        mpIMDBWorkerTask = new HeartBeatMonitor (
            rArgument, *getMessageQueue(), mCommandEvent );
    } else if ( rCommand.compareTo("keepalive", UtlString::ignoreCase) == 0 )
    {
        mpIMDBWorkerTask = new KeepAliveTask (
            rArgument, *getMessageQueue(), mCommandEvent );
    } else if ( rCommand.compareTo("display", UtlString::ignoreCase) == 0 )
    {
        mpIMDBWorkerTask = new DisplayTask (
            rArgument, *getMessageQueue(), mCommandEvent );
    } else if ( rCommand.compareTo("import", UtlString::ignoreCase) == 0 )
    {
        mpIMDBWorkerTask = new ImportTask (
            rArgument, *getMessageQueue(), mCommandEvent );
    } else
    {
    }

    if (mpIMDBWorkerTask != NULL )
    {
        mpIMDBWorkerTask->start();
        // arm the timer to fire periodically, starting one period later
        mpWatchDogTimer->periodicEvery(
            OsTime( rMonitorSecs, 0 ),  // delay
            OsTime( rMonitorSecs, 0 )); // every...
    }
}

// Copy constructor
IMDBTaskMonitor::IMDBTaskMonitor( const IMDBTaskMonitor& rIMDBTaskMonitor ) :
    mErrno(0), mCommandCompleted (FALSE)
{}

// Dtor
IMDBTaskMonitor::~IMDBTaskMonitor()
{
    delete mpTimeoutEvent;
    delete mpWatchDogTimer;
    delete mpIMDBWorkerTask;
}

// Assignment operator
IMDBTaskMonitor&
IMDBTaskMonitor::operator=( const IMDBTaskMonitor& rhs )
{
    if (this == &rhs) // handle the assignment to self case
        return *this;
    return *this;
}

OsStatus
IMDBTaskMonitor::getErrno ( int& rErrnum )
{
    rErrnum = mErrno;
    return OS_SUCCESS;
}

OsStatus
IMDBTaskMonitor::setErrno ( int errnum )
{
    mErrno = errnum;
    return OS_SUCCESS;
}

UtlBoolean
IMDBTaskMonitor::handleMessage ( OsMsg &rMsg )
{
    UtlBoolean returnValue = TRUE;

    // Check for a timer event (indicated by the MsgType)
    if ( ( rMsg.getMsgType() == OsMsg::OS_EVENT ) )
    {
        // Timer Message, see if we still have a working task
        if ( mpIMDBWorkerTask != NULL )
        {
            // test to see if the worker completed the last task
            if ( !mCommandCompleted )
            {
                // firstly stop the timer as things have gone really wrong
                mpWatchDogTimer->stop();

                // kill the worker heartbeat test task and keep the timer alive
                // we'll eventually be killed by the restart script
                // it is important not to exit here as the watchdog will notice and
                // restart us
                osPrintf( "'%s' command [FAILED]\n", mCommandName.data() );
                OsSysLog::add( LOG_FACILITY, PRI_DEBUG, "'%s' command [FAILED]\n", mCommandName.data() );

                // timer expired waiting for the Ping command to complete
                if ( mCommandName.compareTo("heartbeat", UtlString::ignoreCase) == 0 )
                {
                    osPrintf( "Notifying 'pd_monitor' process via 'imdb.bad' file\n" );
                    OsSysLog::add( LOG_FACILITY, PRI_DEBUG, "Notifying pd_monitor process via 'imdb.bad' file\n" );
                    OsFile imdbBrokenIPCFile ( IMDB_BAD_FILE );
                    imdbBrokenIPCFile.touch();
                    imdbBrokenIPCFile.close();
                    mpIMDBWorkerTask->deleteForce();
                    delete mpIMDBWorkerTask;
                    mpIMDBWorkerTask = NULL;
                }

                // waiting around until we're killed off by the watchdog script
                osPrintf ("Waiting for Watchdog Restart (or Ctrl+C)\n");
                OsSysLog::add( LOG_FACILITY, PRI_DEBUG, "Waiting for Watchdog Restart (or Ctrl+C)\n");

                setErrno (1);
            } else
            {   // complete the handshake by toggling the flag
                mCommandCompleted = FALSE;

                // signal the worker thread to immediately kick off another one
                mCommandEvent.signal(0);
            }
        }
    } else if ( (rMsg.getMsgType() == OsMsg::USER_START) && (rMsg.getMsgSubType() == USER_HEARTBEAT_SUCCESS_EVENT) )
    {
        // command completed successfully
        mCommandCompleted = TRUE;
        osPrintf ("%s [OK]\n", mCommandName.data());
        OsSysLog::add(LOG_FACILITY, PRI_DEBUG, "%s [OK]\n", mCommandName.data());
        setErrno (0);
    } else if ( (rMsg.getMsgType() == OsMsg::USER_START) && (rMsg.getMsgSubType() == USER_IMPORT_SUCCESS_EVENT) )
    {
        // import command completed
        mCommandCompleted = TRUE;
        mpWatchDogTimer->stop();
        osPrintf ("%s [OK]\n", mCommandName.data());
        OsSysLog::add(LOG_FACILITY, PRI_DEBUG, "%s [OK]\n", mCommandName.data());
        setErrno (0);
        gShutdownFlag = TRUE;
    } else if ( (rMsg.getMsgType() == OsMsg::USER_START) && (rMsg.getMsgSubType() == USER_DISPLAY_SUCCESS_EVENT) )
    {
        // display command completed
        mCommandCompleted = TRUE;
        mpWatchDogTimer->stop();
        osPrintf ("%s [OK]\n", mCommandName.data());
        OsSysLog::add(LOG_FACILITY, PRI_DEBUG, "%s [OK]\n", mCommandName.data());
        setErrno (0);
        gShutdownFlag = TRUE;
    }
    return( returnValue );
}



syntax highlighted by Code2HTML, v. 0.9.1