//
//
// 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
#if defined(__pingtel_on_posix__)
#include <pwd.h>
#endif
#include <iostream>
#include <signal.h>
// APPLICATION INCLUDES
#include "os/OsFS.h"
#include "os/OsStatus.h"
#include "sipdb/SIPDBManager.h"
#include "IMDBTaskMonitor.h"
// DEFINES
#define DBMONITOR_LOG_DIR "/var/log"
#define DBMONITOR_LOG_FILENAME "dbmonitor.log"
#define DBMONITOR_DEFAULT_LOG_DIR SIPX_LOGDIR
// MACROS
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
typedef void (*sighandler_t)(int);
using namespace std ;
// FUNCTIONS
extern "C" {
void sigHandler( int sig_num );
sighandler_t pt_signal( int sig_num, sighandler_t handler );
}
// FORWARD DECLARATIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS
// GLOBAL VARIABLE INITIALIZATIONS
UtlBoolean removeAllRows = FALSE;
UtlBoolean gShutdownFlag = FALSE;
UtlBoolean gClosingIMDB = FALSE;
OsMutex* gpLockMutex = new OsMutex(OsMutex::Q_FIFO);
OsServerTask* pServerTask = NULL;
/* ============================ FUNCTIONS ================================= */
/** helper method to determine whether we're running as an appropriate user */
OsStatus
isRunningAsValidUser()
{
OsStatus result = OS_FAILED;
UtlString user;
#if defined(__pingtel_on_posix__)
// don't use getlogin as it is not reliable
passwd* pUserInfo = getpwuid( geteuid() );
if ( (pUserInfo != NULL) && (pUserInfo->pw_name != NULL) )
{
user = pUserInfo->pw_name;
}
#else
user = SIPXCHANGE_USERNAME;
#endif
if ( user.compareTo(SIPXCHANGE_USERNAME) == 0 )
{
result = OS_SUCCESS;
}
return result;
}
/**
* Description:
* closes any open connections to the IMDB safely using a mutex lock
*/
void
closeIMDBConnections (int sig_num )
{
// Critical Section here
OsLock lock( *gpLockMutex );
// search for a clue as to whether the signal is from an IMDB assertion
// or not, if it is bypass the code to unregister unregister the PIDs from
// the IMDB
if ( (sig_num == SIGABRT) || (sig_num == SIGSEGV) )
{
// perform some cleanup
} else
{
// Ensure that this process calls close on the IMDB
// this will only access the FastDB if it was opened
// by reference and tables were registers (It checks for
// pFastDB in its destructor and pFastDB is only created
// or opened if a user requests a table
delete SIPDBManager::getInstance();
}
}
/**
* Description:
* This is a replacement for signal() which registers a signal handler but sets
* a flag causing system calls ( namely read() or getchar() ) not to bail out
* upon recepit of that signal. We need this behavior, so we must call
* sigaction() manually.
*/
sighandler_t
pt_signal( int sig_num, sighandler_t handler)
{
#if defined(__pingtel_on_posix__)
struct sigaction action[2];
action[0].sa_handler = handler;
sigemptyset(&action[0].sa_mask);
action[0].sa_flags = 0;
sigaction ( sig_num, &action[0], &action[1] );
return action[1].sa_handler;
#else
return signal( sig_num, handler );
#endif
}
/**
* Description:
* This is the signal handler, When called this sets the
* global gShutdownFlag allowing the main processing
* loop to exit cleanly.
*/
void
sigHandler( int sig_num )
{
// set a global shutdown flag
gShutdownFlag = TRUE;
// Unregister interest in the signal to prevent recursive callbacks
pt_signal( sig_num, SIG_DFL );
// Minimize the chance that we loose log data
closeIMDBConnections( sig_num );
}
void
setLogLevel()
{
OsSysLog::setLoggingPriority( PRI_DEBUG );
}
OsStatus
getLogFilePath ( UtlString& logFilePath )
{
// Make sure that the SIPXCHANGE_HOME ends with
// a trailing file separator character
char *sipxHomeEnv = getenv ( "SIPXCHANGE_HOME" );
OsPath path;
if ( sipxHomeEnv != NULL )
{
UtlString sipxHome = sipxHomeEnv;
// if the last character is a separator strip it.
if ( sipxHome ( sipxHome.length() -1 ) == OsPath::separator )
sipxHome = sipxHome(0, sipxHome.length()-1);
if ( OsFileSystem::exists( sipxHome + DBMONITOR_LOG_DIR) )
{
path = sipxHome + DBMONITOR_LOG_DIR;
} else
{ // set to current working directory as the dir does not exist
OsFileSystem::getWorkingDirectory(path);
}
} else // Environment Variable is not defined check default location
{
if ( OsFileSystem::exists( DBMONITOR_DEFAULT_LOG_DIR ) )
{
// Search in DBMONITOR_DEFAULT_LOG_DIR (which is SIPX_LOGDIR).
path = DBMONITOR_DEFAULT_LOG_DIR;
} else
{
// set to current working directory
OsFileSystem::getWorkingDirectory(path);
}
}
// now that we have the path to the logfile directory
// append the name of the log file
path += OsPath::separator + DBMONITOR_LOG_FILENAME;
// Finally translate path to native path,
// this will ensure the volume is set correctly
OsPath nativePath ;
path.getNativePath(nativePath);
logFilePath = nativePath ;
return OS_SUCCESS;
}
// Print out some command line interface help
void
usage()
{
cout << "in memory database utility" << endl;
cout << "==========================" << endl;
cout << "to populate IMDB tables from an XML file:" << endl;
cout << " import xmlfile" << endl;
cout << "to display the contents of a table:" << endl;
cout << " display tablename [retrydelaysecs(30 default)]" << endl;
cout << "to monitor the IMDB for and write an imdb.bad file if it times out:" << endl;
cout << " heartbeat [processinfo|#transactiontime(s)] [heartbeatintervalsecs(30s)]" << endl;
cout << "to preload the IMDB tables:" << endl;
cout << " keepalive tablename" << endl;
cout << "where 'tablename' is [credential|dialbyname|permission|registration|alias|subscription|extension|huntgroup|authexception|processinfo]" << endl;
}
void
doWaitLoop()
{
while ( !gShutdownFlag )
OsTask::delay( 500 );
if ( pServerTask )
pServerTask->requestShutdown();
}
/**
* Launches a worker thread and waits for it to finish
*
* @param rCommand
* @param rCommandArgument
* @param rTimeoutSecs
*
* @return
*/
int
launchWorkerTask (
const UtlString& rCommand,
const UtlString& rCommandArgument,
const int& rTimeoutSecs )
{
int status = 0;
pServerTask = new IMDBTaskMonitor( rCommand, rCommandArgument, rTimeoutSecs );
pServerTask->start();
doWaitLoop();
pServerTask->getErrno( status );
return status;
}
/**
* Main entry point for the test utility
*
* @param argc
* @param argv
*
* @return
*/
int
main( int argc, char *argv[] )
{
// initialize exit status to success
int exitCode = EXIT_SUCCESS;
// Register Signal handlers to close IMDB
pt_signal(SIGINT, sigHandler); // Trap Ctrl-C on NT
pt_signal(SIGILL, sigHandler);
pt_signal(SIGABRT, sigHandler); // Abort signal 6
pt_signal(SIGFPE, sigHandler); // Floading Point Exception
pt_signal(SIGSEGV, sigHandler); // Address access violations signal 11
pt_signal(SIGTERM, sigHandler); // Trap kill -15 on UNIX
#if defined(__pingtel_on_posix__)
pt_signal(SIGHUP, sigHandler); // Hangup
pt_signal(SIGQUIT, sigHandler);
pt_signal(SIGPIPE, SIG_IGN); // Handle TCP Failure
pt_signal(SIGBUS, sigHandler);
pt_signal(SIGSYS, sigHandler);
pt_signal(SIGXCPU, sigHandler);
pt_signal(SIGXFSZ, sigHandler);
pt_signal(SIGUSR1, sigHandler);
pt_signal(SIGUSR2, sigHandler);
#endif
cout << "IMDB Test Harness" << endl;
// see if we're running as user sipxchange, and warn user if we are not
if ( isRunningAsValidUser() != OS_SUCCESS )
{
cout << "CAUTION: Using this program as any user other than 'sipxchange'\n"
<< " on a production system may cause database problems\n"
<< " that can disable the system. Use this program only\n"
<< " as instructed by the Pingtel Technical Assistance Center.\n"
<< "\n"
<< endl;
}
UtlString logFilePath;
if ( getLogFilePath ( logFilePath ) == OS_SUCCESS )
{
// Initialize the logger.
OsSysLog::initialize(0, "dbmonitor" );
OsSysLog::setOutputFile(0, logFilePath );
setLogLevel();
OsSysLog::add(LOG_FACILITY, PRI_DEBUG,
"sipdbtest - Entering main");
// valid user so check arguments, import/display/heartbeat
if( argc > 2 )
{
int defaultTimeoutSecs = 30;
if (argc > 3)
defaultTimeoutSecs = atoi( argv[3] );
UtlString cmd = argv[1];
if ( (cmd.compareTo("heartbeat", UtlString::ignoreCase) != 0) &&
(cmd.compareTo("keepalive", UtlString::ignoreCase) != 0) &&
(cmd.compareTo("display", UtlString::ignoreCase) != 0) &&
(cmd.compareTo("import", UtlString::ignoreCase) != 0) )
{
usage();
exitCode = EXIT_BADSYNTAX;
}
else
exitCode = launchWorkerTask (
argv[1], // command
argv[2], // command argument (heartbeat (this is tableinfo/txdelay(s))
defaultTimeoutSecs ); // the monitor time
} else {
usage();
exitCode = EXIT_BADSYNTAX;
}
}
if ( exitCode == EXIT_SUCCESS )
{
// unregister this process's database references from the IMDB
cout << "Cleanup...Start" << endl;
closeIMDBConnections(-1);
cout << "Cleanup...Finished" << endl;
}
return exitCode;
}
syntax highlighted by Code2HTML, v. 0.9.1