//
//
// 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
#include <stdio.h>
#include <signal.h>
#if defined(_WIN32)
#include <windows.h>
#elif defined(__pingtel_on_posix__)
#include <unistd.h>
#endif
#include <os/OsFS.h>
#include <os/OsConfigDb.h>
#include <os/OsSocket.h>
#include <os/OsTask.h>
#include <net/SipUserAgent.h>
#include <net/NameValueTokenizer.h>
#include <xmlparser/tinyxml.h>
#include <SipRouter.h>
#include <ForwardRules.h>
#include <ForkingProxyCseObserver.h>
#ifndef SIPX_VERSION
# include "sipxproxy-buildstamp.h"
# define SIPX_VERSION SipXproxyVersion
# define SIPX_BUILD SipXproxyBuildStamp
#else
# define SIPX_BUILD ""
#endif
//uncomment next line to enable bound checker checking with 'b' key
//#define BOUNDS_CHECKER
#ifdef BOUNDS_CHECKER
#include "D:\Program Files\Compuware\BoundsChecker\ERptApi\apilib.h"
#pragma comment(lib, "D:\\Program Files\\Compuware\\BoundsChecker\\ERptApi\\nmapi.lib")
#endif
#define CONFIG_ETC_DIR SIPX_CONFDIR
#define FORWARDING_RULES_FILENAME "forwardingrules.xml"
#define SIP_PROXY_LOG "sipproxy.log"
#define CONFIG_LOG_DIR SIPX_LOGDIR
#define LOG_FACILITY FAC_SIP
#define CALL_STATE_LOG_FILE_DEFAULT SIPX_LOGDIR "/sipproxy_callstate.log"
// Configuration names pulled from config-file
#define CONFIG_SETTING_LOG_LEVEL "SIP_PROXY_LOG_LEVEL"
#define CONFIG_SETTING_LOG_CONSOLE "SIP_PROXY_LOG_CONSOLE"
#define CONFIG_SETTING_LOG_DIR "SIP_PROXY_LOG_DIR"
#define CONFIG_SETTING_CALL_STATE "SIP_PROXY_CALL_STATE"
#define CONFIG_SETTING_CALL_STATE_LOG "SIP_PROXY_CALL_STATE_LOG"
static const char* CONFIG_SETTING_CALL_STATE_DB =
"SIP_PROXY_CALL_STATE_DB";
static const char* CONFIG_SETTING_CALL_STATE_DB_HOST =
"SIP_PROXY_CALL_STATE_DB_HOST";
static const char* CONFIG_SETTING_CALL_STATE_DB_NAME =
"SIP_PROXY_CALL_STATE_DB_NAME";
static const char* CONFIG_SETTING_CALL_STATE_DB_USER =
"SIP_PROXY_CALL_STATE_DB_USER";
static const char* CONFIG_SETTING_CALL_STATE_DB_DRIVER =
"SIP_PROXY_CALL_STATE_DB_DRIVER";
static const char* CALL_STATE_DATABASE_HOST =
"localhost";
static const char* CALL_STATE_DATABASE_NAME =
"SIPXCDR";
static const char* CALL_STATE_DATABASE_USER =
"postgres";
static const char* CALL_STATE_DATABASE_DRIVER =
"{PostgreSQL}";
#define PRINT_ROUTE_RULE(APPEND_STRING, FROM_HOST, TO_HOST) \
APPEND_STRING.append("\t<route mappingType=\"local\">\n\t\t<routeFrom>"); \
APPEND_STRING.append(FROM_HOST); \
APPEND_STRING.append("</routeFrom>\n\t\t<routeTo>"); \
APPEND_STRING.append(TO_HOST); \
APPEND_STRING.append("</routeTo>\n\t</route>\n");
// TYPEDEFS
typedef void (*sighandler_t)(int);
// FUNCTIONS
extern "C" {
void sigHandler( int sig_num );
sighandler_t pt_signal( int sig_num, sighandler_t handler );
}
// GLOBALS
UtlBoolean gShutdownFlag = FALSE;
/**
* 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
OsSysLog::flush();
if (SIGTERM == sig_num)
{
OsSysLog::add( LOG_FACILITY, PRI_INFO, "sigHandler: terminate signal received.");
}
else
{
OsSysLog::add( LOG_FACILITY, PRI_CRIT, "sigHandler: caught signal: %d", sig_num );
}
OsSysLog::add( LOG_FACILITY, PRI_CRIT, "sigHandler: closing IMDB connections" );
OsSysLog::flush();
}
// Initialize the OsSysLog
void initSysLog(OsConfigDb* pConfig)
{
UtlString logLevel; // Controls Log Verbosity
UtlString consoleLogging; // Enable console logging by default?
UtlString fileTarget; // Path to store log file.
UtlBoolean bSpecifiedDirError ; // Set if the specified log dir does not
// exist
struct tagPrioriotyLookupTable
{
const char* pIdentity;
OsSysLogPriority ePriority;
};
struct tagPrioriotyLookupTable lkupTable[] =
{
{ "DEBUG", PRI_DEBUG},
{ "INFO", PRI_INFO},
{ "NOTICE", PRI_NOTICE},
{ "WARNING", PRI_WARNING},
{ "ERR", PRI_ERR},
{ "CRIT", PRI_CRIT},
{ "ALERT", PRI_ALERT},
{ "EMERG", PRI_EMERG},
};
OsSysLog::initialize(0, "SipProxy");
//
// Get/Apply Log Filename
//
fileTarget.remove(0) ;
if ((pConfig->get(CONFIG_SETTING_LOG_DIR, fileTarget) != OS_SUCCESS) ||
fileTarget.isNull() || !OsFileSystem::exists(fileTarget))
{
bSpecifiedDirError = !fileTarget.isNull() ;
// If the log file directory exists use that, otherwise place the log
// in the current directory
OsPath workingDirectory;
if (OsFileSystem::exists(CONFIG_LOG_DIR))
{
fileTarget = CONFIG_LOG_DIR;
OsPath path(fileTarget);
path.getNativePath(workingDirectory);
osPrintf("%s : %s\n", CONFIG_SETTING_LOG_DIR, workingDirectory.data()) ;
OsSysLog::add(FAC_SIP, PRI_INFO, "%s : %s", CONFIG_SETTING_LOG_DIR, workingDirectory.data()) ;
}
else
{
OsPath path;
OsFileSystem::getWorkingDirectory(path);
path.getNativePath(workingDirectory);
osPrintf("%s : %s\n", CONFIG_SETTING_LOG_DIR, workingDirectory.data()) ;
OsSysLog::add(FAC_SIP, PRI_INFO, "%s : %s", CONFIG_SETTING_LOG_DIR, workingDirectory.data()) ;
}
fileTarget = workingDirectory +
OsPathBase::separator +
SIP_PROXY_LOG;
}
else
{
bSpecifiedDirError = false ;
osPrintf("%s : %s\n", CONFIG_SETTING_LOG_DIR, fileTarget.data()) ;
OsSysLog::add(FAC_SIP, PRI_INFO, "%s : %s", CONFIG_SETTING_LOG_DIR, fileTarget.data()) ;
fileTarget = fileTarget +
OsPathBase::separator +
SIP_PROXY_LOG;
}
OsSysLog::setOutputFile(0, fileTarget) ;
//
// Get/Apply Log Level
//
if ((pConfig->get(CONFIG_SETTING_LOG_LEVEL, logLevel) != OS_SUCCESS) ||
logLevel.isNull())
{
logLevel = "ERR";
}
logLevel.toUpper();
OsSysLogPriority priority = PRI_ERR;
int iEntries = sizeof(lkupTable)/sizeof(struct tagPrioriotyLookupTable);
for (int i=0; i<iEntries; i++)
{
if (logLevel == lkupTable[i].pIdentity)
{
priority = lkupTable[i].ePriority;
osPrintf("%s : %s\n", CONFIG_SETTING_LOG_LEVEL, lkupTable[i].pIdentity) ;
OsSysLog::add(FAC_SIP, PRI_INFO, "%s : %s", CONFIG_SETTING_LOG_LEVEL, lkupTable[i].pIdentity) ;
break;
}
}
OsSysLog::setLoggingPriority(priority);
//
// Get/Apply console logging
//
if ((pConfig->get(CONFIG_SETTING_LOG_CONSOLE, consoleLogging) ==
OS_SUCCESS))
{
consoleLogging.toUpper();
if (consoleLogging == "ENABLE")
{
OsSysLog::enableConsoleOutput(true);
osPrintf("%s : %s\n", CONFIG_SETTING_LOG_CONSOLE, "ENABLE") ;
OsSysLog::add(FAC_SIP, PRI_INFO, "%s : %s", CONFIG_SETTING_LOG_CONSOLE, "ENABLE") ;
}
else
{
osPrintf("%s : %s\n", CONFIG_SETTING_LOG_CONSOLE, "DISABLE") ;
OsSysLog::add(FAC_SIP, PRI_INFO, "%s : %s", CONFIG_SETTING_LOG_CONSOLE, "DISABLE") ;
}
}
if (bSpecifiedDirError)
{
OsSysLog::add(FAC_LOG, PRI_CRIT, "Cannot access %s directory; please check configuration.", CONFIG_SETTING_LOG_DIR);
}
}
/** The main entry point to the proxy */
int
main(int argc, char* argv[])
{
// 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);
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
UtlString argString;
UtlBoolean interactiveSet = false;
for(int argIndex = 1; argIndex < argc; argIndex++)
{
osPrintf("arg[%d]: %s\n", argIndex, argv[argIndex]);
argString = argv[argIndex];
NameValueTokenizer::frontBackTrim(&argString, "\t ");
if(argString.compareTo("-v") == 0)
{
osPrintf("Version: %s %s\n", SIPX_VERSION, SIPX_BUILD);
return(1);
}
else if( argString.compareTo("-i") == 0)
{
interactiveSet = true;
osPrintf("Entering Interactive Mode\n");
}
else
{
osPrintf("usage: %s [-v] [-i]\nwhere:\n -v provides the software version\n"
" -i starts the server in an interactive mode\n",
argv[0]);
return(1);
}
}
int proxyTcpPort;
int proxyUdpPort;
int proxyTlsPort;
UtlString domainName;
UtlString proxyRecordRoute;
int maxForwards;
OsConfigDb configDb;
UtlString ipAddress;
OsSocket::getHostIp(&ipAddress);
/*Config files which are specific to a component
(e.g. mappingrules.xml is to sipregistrar) Use the
following logic:
1) If directory ../etc exists:
The path to the data file is as follows
../etc/<data-file-name>
2) Else the path is assumed to be:
./<data-file-name>
*/
OsPath workingDirectory;
if ( OsFileSystem::exists( CONFIG_ETC_DIR ) )
{
workingDirectory = CONFIG_ETC_DIR;
OsPath path(workingDirectory);
path.getNativePath(workingDirectory);
}
else
{
OsPath path;
OsFileSystem::getWorkingDirectory(path);
path.getNativePath(workingDirectory);
}
UtlString ConfigfileName = workingDirectory +
OsPathBase::separator +
"proxy-config";
if(configDb.loadFromFile(ConfigfileName) == OS_SUCCESS)
{
osPrintf("Found config file: %s\n", ConfigfileName.data());
}
else
{
configDb.set("SIP_PROXY_UDP_PORT", "5060");
configDb.set("SIP_PROXY_TCP_PORT", "5060");
configDb.set("SIP_PROXY_TLS_PORT", "5061");
//configDb.set("SIP_PROXY_DOMAIN_NAME", "");
//configDb.set("SIP_PROXY_RECORD_ROUTE", "DISABLE");
configDb.set("SIP_PROXY_MAX_FORWARDS", "");
configDb.set("SIP_PROXY_USE_AUTH_SERVER", "");
configDb.set("SIP_PROXY_AUTH_SERVER", "");
configDb.set("SIP_PROXY_DEFAULT_EXPIRES", "");
configDb.set("SIP_PROXY_DEFAULT_SERIAL_EXPIRES", "");
configDb.set("SIP_PROXY_HOST_ALIASES", "");
//configDb.set("SIP_PROXY_BRANCH_TIMEOUT", "");
configDb.set("SIP_PROXY_STALE_TCP_TIMEOUT", "");
configDb.set(CONFIG_SETTING_LOG_DIR, "");
configDb.set(CONFIG_SETTING_LOG_LEVEL, "");
configDb.set(CONFIG_SETTING_LOG_CONSOLE, "");
configDb.set(CONFIG_SETTING_CALL_STATE, "DISABLE");
configDb.set(CONFIG_SETTING_CALL_STATE_LOG, "");
configDb.set(CONFIG_SETTING_CALL_STATE_DB, "DISABLE");
configDb.set(CONFIG_SETTING_CALL_STATE_DB_HOST, CALL_STATE_DATABASE_HOST);
configDb.set(CONFIG_SETTING_CALL_STATE_DB_NAME, CALL_STATE_DATABASE_NAME);
configDb.set(CONFIG_SETTING_CALL_STATE_DB_USER, CALL_STATE_DATABASE_USER);
configDb.set(CONFIG_SETTING_CALL_STATE_DB_DRIVER, CALL_STATE_DATABASE_DRIVER);
if(configDb.storeToFile(ConfigfileName) != OS_SUCCESS)
{
osPrintf("Could not write config file: %s\n", ConfigfileName.data());
}
}
// Initialize the OsSysLog...
initSysLog(&configDb);
OsSysLog::add(FAC_SIP, PRI_INFO, ">>>>>>>>>>>>>>>> Starting - version %s build %s",
SIPX_VERSION, SIPX_BUILD
);
configDb.get("SIP_PROXY_DOMAIN_NAME", domainName);
if(domainName.isNull())
{
domainName = ipAddress;
}
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_DOMAIN_NAME : %s", domainName.data());
osPrintf("SIP_PROXY_DOMAIN_NAME : %s\n", domainName.data());
proxyUdpPort = configDb.getPort("SIP_PROXY_UDP_PORT") ;
if (!portIsValid(proxyUdpPort))
{
proxyUdpPort = 5060;
}
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_UDP_PORT : %d", proxyUdpPort);
proxyTcpPort = configDb.getPort("SIP_PROXY_TCP_PORT") ;
if (!portIsValid(proxyTcpPort))
{
proxyTcpPort = 5060;
}
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_TCP_PORT : %d", proxyTcpPort);
proxyTlsPort = configDb.getPort("SIP_PROXY_TLS_PORT") ;
if (!portIsValid(proxyTlsPort))
{
proxyTlsPort = 5061;
}
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_TLS_PORT : %d", proxyTlsPort);
configDb.get("SIP_PROXY_RECORD_ROUTE", proxyRecordRoute);
UtlBoolean recordRouteEnabled = FALSE;
proxyRecordRoute.toLower();
if(proxyRecordRoute.compareTo("enable") == 0)
{
recordRouteEnabled = TRUE;
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_RECORD_ROUTE : ENABLE");
osPrintf("SIP_PROXY_RECORD_ROUTE : ENABLE\n");
}
configDb.get("SIP_PROXY_MAX_FORWARDS", maxForwards);
if(maxForwards <= 0) maxForwards = SIP_DEFAULT_MAX_FORWARDS;
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_MAX_FORWARDS : %d", maxForwards);
osPrintf("SIP_PROXY_MAX_FORWARDS : %d\n", maxForwards);
int branchTimeout = -1;
configDb.get("SIP_PROXY_BRANCH_TIMEOUT", branchTimeout);
if(branchTimeout < 4)
{
branchTimeout = 24;
}
UtlBoolean authEnabled = TRUE;
UtlString authServerEnabled;
configDb.get("SIP_PROXY_USE_AUTH_SERVER", authServerEnabled);
authServerEnabled.toLower();
if(authServerEnabled.compareTo("disable") == 0)
{
authEnabled = FALSE;
}
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_USE_AUTH_SERVER : %s", authEnabled ? "ENABLE" : "DISABLE");
osPrintf("SIP_PROXY_USE_AUTH_SERVER : %s\n", authEnabled ? "ENABLE" : "DISABLE");
UtlString authServer;
configDb.get("SIP_PROXY_AUTH_SERVER", authServer);
if(authEnabled &&
authServer.isNull())
{
authServer = ipAddress;
authServer.append(":5080");
}
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_AUTH_SERVER : %s", authServer.data());
osPrintf("SIP_PROXY_AUTH_SERVER : %s\n", authServer.data());
int defaultExpires;
int defaultSerialExpires;
configDb.get("SIP_PROXY_DEFAULT_EXPIRES", defaultExpires);
configDb.get("SIP_PROXY_DEFAULT_SERIAL_EXPIRES", defaultSerialExpires);
if(defaultExpires <= 0 ||
defaultExpires > 180) defaultExpires = 180;
if(defaultSerialExpires <= 0 ||
defaultSerialExpires >= defaultExpires) defaultSerialExpires = 20;
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_DEFAULT_EXPIRES : %d", defaultExpires);
osPrintf("SIP_PROXY_DEFAULT_EXPIRES : %d\n", defaultExpires);
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_DEFAULT_SERIAL_EXPIRES : %d", defaultSerialExpires);
osPrintf("SIP_PROXY_DEFAULT_SERIAL_EXPIRES : %d\n", defaultSerialExpires);
// Set the maximum amount of time that TCP connections can
// stay around when they are not used.
int staleTcpTimeout = 3600;
UtlString staleTcpTimeoutStr;
// Check for missing parameter or empty value
configDb.get("SIP_PROXY_STALE_TCP_TIMEOUT", staleTcpTimeoutStr);
if (staleTcpTimeoutStr.isNull())
{
staleTcpTimeout = 3600;
}
else
{
// get the parameter value as an integer
configDb.get("SIP_PROXY_STALE_TCP_TIMEOUT", staleTcpTimeout);
}
if(staleTcpTimeout <= 0) staleTcpTimeout = -1;
else if(staleTcpTimeout < 180) staleTcpTimeout = 180;
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_STALE_TCP_TIMEOUT : %d",
staleTcpTimeout);
osPrintf("SIP_PROXY_STALE_TCP_TIMEOUT : %d\n", staleTcpTimeout);
int maxNumSrvRecords = -1;
configDb.get("SIP_PROXY_DNSSRV_MAX_DESTS", maxNumSrvRecords);
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_DNSSRV_MAX_DESTS : %d",
maxNumSrvRecords);
// If explicitly set to a valid number
if(maxNumSrvRecords > 0)
{
osPrintf("SIP_PROXY_DNSSRV_MAX_DESTS : %d\n", maxNumSrvRecords);
}
else
{
maxNumSrvRecords = 4;
}
int dnsSrvTimeout = -1; //seconds
configDb.get("SIP_PROXY_DNSSRV_TIMEOUT", dnsSrvTimeout);
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_DNSSRV_TIMEOUT : %d",
dnsSrvTimeout);
// If explicitly set to a valid number
if(dnsSrvTimeout > 0)
{
osPrintf("SIP_PROXY_DNSSRV_TIMEOUT : %d\n", dnsSrvTimeout);
}
else
{
dnsSrvTimeout = 4;
}
UtlString hostAliases;
configDb.get("SIP_PROXY_HOST_ALIASES", hostAliases);
if(hostAliases.isNull())
{
hostAliases = ipAddress;
char portBuf[20];
sprintf(portBuf, ":%d", proxyUdpPort);
hostAliases.append(portBuf);
}
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_HOST_ALIASES : %s",
hostAliases.data());
osPrintf("SIP_PROXY_HOST_ALIASES : %s\n", hostAliases.data());
UtlString enableCallStateObserverSetting;
configDb.get(CONFIG_SETTING_CALL_STATE, enableCallStateObserverSetting);
bool enableCallStateLogObserver;
if ( (enableCallStateObserverSetting.isNull())
|| (0== enableCallStateObserverSetting.compareTo("disable", UtlString::ignoreCase))
)
{
enableCallStateLogObserver = false;
}
else if (0 == enableCallStateObserverSetting.compareTo("enable", UtlString::ignoreCase))
{
enableCallStateLogObserver = true;
}
else
{
enableCallStateLogObserver = false;
OsSysLog::add(FAC_SIP, PRI_ERR, "SipForkingProxyMain invalid configuration value for "
CONFIG_SETTING_CALL_STATE " '%s' - should be 'enable' or 'disable'",
enableCallStateObserverSetting.data()
);
}
OsSysLog::add(FAC_SIP, PRI_INFO, CONFIG_SETTING_CALL_STATE " : %s",
enableCallStateLogObserver ? "ENABLE" : "DISABLE" );
UtlString callStateLogFileName;
if (enableCallStateLogObserver)
{
configDb.get(CONFIG_SETTING_CALL_STATE_LOG, callStateLogFileName);
if (callStateLogFileName.isNull())
{
callStateLogFileName = CALL_STATE_LOG_FILE_DEFAULT;
}
OsSysLog::add(FAC_SIP, PRI_INFO, CONFIG_SETTING_CALL_STATE_LOG " : %s",
callStateLogFileName.data());
}
// Check if CSE logging should go into a database
UtlString enableCallStateDbObserverSetting;
configDb.get(CONFIG_SETTING_CALL_STATE_DB, enableCallStateDbObserverSetting);
bool enableCallStateDbObserver;
if ( (enableCallStateDbObserverSetting.isNull())
|| ((0 == enableCallStateDbObserverSetting.compareTo("disable", UtlString::ignoreCase)))
)
{
enableCallStateDbObserver = false;
}
else if (0 == enableCallStateDbObserverSetting.compareTo("enable", UtlString::ignoreCase))
{
enableCallStateDbObserver = true;
}
else
{
enableCallStateDbObserver = false;
OsSysLog::add(FAC_SIP, PRI_ERR, "SipForkingProxyMain:: invalid configuration value for "
"%s '%s' - should be 'enable' or 'disable'", CONFIG_SETTING_CALL_STATE_DB,
enableCallStateDbObserverSetting.data()
);
}
OsSysLog::add(FAC_SIP, PRI_INFO, "%s : %s", CONFIG_SETTING_CALL_STATE_DB,
enableCallStateDbObserver ? "ENABLE" : "DISABLE" );
UtlString callStateDbHostName;
UtlString callStateDbName;
UtlString callStateDbUserName;
UtlString callStateDbDriver;
if (enableCallStateDbObserver)
{
configDb.get(CONFIG_SETTING_CALL_STATE_DB_HOST, callStateDbHostName);
if (callStateDbHostName.isNull())
{
callStateDbHostName = CALL_STATE_DATABASE_HOST;
}
OsSysLog::add(FAC_SIP, PRI_INFO, "%s : %s", CONFIG_SETTING_CALL_STATE_DB_HOST,
callStateDbHostName.data());
configDb.get(CONFIG_SETTING_CALL_STATE_DB_NAME, callStateDbName);
if (callStateDbName.isNull())
{
callStateDbName = CALL_STATE_DATABASE_NAME;
}
OsSysLog::add(FAC_SIP, PRI_INFO, "%s : %s", CONFIG_SETTING_CALL_STATE_DB_NAME,
callStateDbName.data());
configDb.get(CONFIG_SETTING_CALL_STATE_DB_USER, callStateDbUserName);
if (callStateDbUserName.isNull())
{
callStateDbUserName = CALL_STATE_DATABASE_USER;
}
OsSysLog::add(FAC_SIP, PRI_INFO, "%s : %s", CONFIG_SETTING_CALL_STATE_DB_USER,
callStateDbUserName.data());
configDb.get(CONFIG_SETTING_CALL_STATE_DB_DRIVER, callStateDbDriver);
if (callStateDbDriver.isNull())
{
callStateDbDriver = CALL_STATE_DATABASE_DRIVER;
}
OsSysLog::add(FAC_SIP, PRI_INFO, "%s : %s", CONFIG_SETTING_CALL_STATE_DB_DRIVER,
callStateDbDriver.data());
}
// Select logging method - database takes priority over XML file
if (enableCallStateLogObserver && enableCallStateDbObserver)
{
enableCallStateLogObserver = false;
OsSysLog::add(FAC_SIP, PRI_WARNING, "SipForkingProxyMain:: both XML and database call state "
"logging was enabled - turning off XML log, only use database logging");
}
// This is an obnoxious special option to work around a
// problem with Sonus gateways. The Sonus proxy or redirect
// server gives a list of possible gateways to recurse in a
// 300 response. It does not assign any Q values so the proxy
// gets the impression that it should fork them all in parallel.
// When this option is enabled we recurse only the one with the
// highest Q value.
UtlString recurseOnlyOne300String;
configDb.get("SIP_PROXY_SPECIAL_300", recurseOnlyOne300String);
recurseOnlyOne300String.toLower();
UtlBoolean recurseOnlyOne300 = FALSE;
if(recurseOnlyOne300String.compareTo("enable") == 0)
{
recurseOnlyOne300 = TRUE;
OsSysLog::add(FAC_SIP, PRI_INFO, "SIP_PROXY_SPECIAL_300 : ENABLE");
osPrintf("SIP_PROXY_SPECIAL_300 : ENABLE\n");
}
// Get the mapped and local domains
OsConfigDb mappedDomains ;
configDb.getSubHash("SIP_DOMAINS.", mappedDomains);
if(mappedDomains.isEmpty())
{
//UtlString proxydomain(ipAddress);
//proxydomain.append(":5060");
//UtlString registryDomain(ipAddress);
//registryDomain.append(":4000");
//mappedDomains.set(proxydomain, registryDomain.data());
}
else
{
OsSysLog::add(FAC_SIP, PRI_WARNING, "WARNING: SIP_DOMAINS. parameters IGNORED");
}
// Initialize the domaim mapping from the routeRules XML
// file
//OsConfigDb mapRulesDb;
UtlString fileName ;
fileName = workingDirectory +
OsPathBase::separator +
FORWARDING_RULES_FILENAME ;
ForwardRules forwardingRules;
OsFile ruleFile(fileName);
UtlBoolean useDefaultRules = FALSE;
if(ruleFile.exists())
{
if(OS_SUCCESS != forwardingRules.loadMappings(fileName))
{
OsSysLog::add(FAC_SIP, PRI_WARNING, "WARNING: Failed to load: %s",
fileName.data());
osPrintf("WARNING: Failed to load: %s\n", fileName.data());
useDefaultRules = TRUE;
}
}
else
{
OsSysLog::add(FAC_SIP, PRI_INFO, "%s not found",
fileName.data());
osPrintf("%s not found\n",
fileName.data());
useDefaultRules = TRUE;
}
if(useDefaultRules)
{
OsSysLog::add(FAC_SIP, PRI_INFO, "using default forwarding rules");
osPrintf("using default forwarding rules\n");
UtlString localDomain;
OsSocket::getDomainName(localDomain);
UtlString hostName;
OsSocket::getHostName(&hostName);
UtlString ipAddress;
OsSocket::getHostIp(&ipAddress);
UtlString fqhn(hostName);
fqhn.append('.');
fqhn.append(localDomain);
forwardingRules.buildDefaultRules(localDomain.data(),
hostName.data(),
ipAddress.data(),
fqhn,
proxyUdpPort);
}
#ifdef TEST_PRINT
{ // scope the test stuff
SipMessage foo;
const char* uri = "sip:10.1.20.3:5100";
const char* method = "ACK"; //SIP_SUBSCRIBE_METHOD;
const char* eventType = "sip-config"; //SIP_EVENT_CONFIG;
foo.setRequestData(method,
uri, //uri,
"sip:1234@doty.com", // fromField,
"\"lajdflsdk ff\"<sip:laksdjf@1234.x.com>", // toField,
"lkadsj902387", // callId,
123, // CSeq,
"sip:10.1.1.123");// contactUrl
// Set the event type
foo.setHeaderValue(SIP_EVENT_FIELD,
eventType, // event type
0);
Url msgUrl(uri);
UtlString routeTo;
UtlString routeType;
OsStatus routeStatus = forwardingRules.getRoute(msgUrl,
foo,
routeTo,
routeType);
Url msgRouteToUri(routeTo);
osPrintf("Message:\n\tmethod: %s\n\turi: %s\n\tevent: %s\nRouted:\n\tstring: %s\n\turi: %s\n\ttype: %s\n",
method, uri, eventType, routeTo.data(), msgRouteToUri.toString().data(), routeType.data());
if(routeStatus != OS_SUCCESS)
osPrintf("forwardingRules.getRoute returned: %d\n",
routeStatus);
}
#endif // TEST_PRINT
// Start the sip stack
SipUserAgent sipUserAgent(proxyTcpPort,
proxyUdpPort,
proxyTlsPort,
NULL, // public IP address (nopt used in proxy)
NULL, // default user (not used in proxy)
NULL, // default SIP address (not used in proxy)
(authEnabled && !authServer.isNull()) ? authServer.data() : NULL,
NULL, // directory server
NULL, // registry server
NULL, // auth scheme
NULL, //auth realm
NULL, // auth DB
NULL, // auth user IDs
NULL, // auth passwords
NULL, // nat ping URL
0, // nat ping frequency
"PING", // nat ping method
NULL, // line mgr
SIP_DEFAULT_RTT, // first resend timeout
TRUE, // default to UA transaction
SIPUA_DEFAULT_SERVER_UDP_BUFFER_SIZE, // socket layer read buffer size
SIPUA_DEFAULT_SERVER_OSMSG_QUEUE_SIZE // OsServerTask message queue size
);
sipUserAgent.setIsUserAgent(FALSE);
sipUserAgent.setUserAgentHeaderProperty("sipX/forkingproxy");
sipUserAgent.setMaxForwards(maxForwards);
sipUserAgent.setDnsSrvTimeout(dnsSrvTimeout);
sipUserAgent.setMaxSrvRecords(maxNumSrvRecords);
sipUserAgent.setDefaultExpiresSeconds(defaultExpires);
sipUserAgent.setDefaultSerialExpiresSeconds(defaultSerialExpires);
sipUserAgent.setMaxTcpSocketIdleTime(staleTcpTimeout);
sipUserAgent.setHostAliases(hostAliases);
sipUserAgent.setRecurseOnlyOne300Contact(recurseOnlyOne300);
sipUserAgent.start();
UtlString buffer;
// Create and start a router to route stuff either
// to a local server or on out to the real world
SipRouter router(sipUserAgent,
forwardingRules,
authEnabled,
authServer.data(),
recordRouteEnabled);
router.start();
ForkingProxyCseObserver* cseObserver = NULL;
CallStateEventWriter* pEventWriter = NULL;
if (enableCallStateLogObserver)
{
// Set up the call state event log file
pEventWriter = new CallStateEventWriter_XML(callStateLogFileName.data());
}
else if (enableCallStateDbObserver)
{
pEventWriter = new CallStateEventWriter_DB(callStateDbName.data(),
callStateDbHostName.data(),
callStateDbUserName,
callStateDbDriver);
}
if (pEventWriter)
{
// get the identifier for this observer
int protocol = OsSocket::UDP;
UtlString domainName;
int port;
sipUserAgent.getViaInfo(protocol, domainName, port);
char portString[12];
sprintf(portString,":%d", port);
domainName.append(portString);
// and start the observer
cseObserver = new ForkingProxyCseObserver(sipUserAgent, domainName, pEventWriter);
cseObserver->start();
}
else
{
// Only log error if any event logging was enabled
if (enableCallStateLogObserver || enableCallStateDbObserver)
{
OsSysLog::add(FAC_SIP, PRI_ERR,
"SipForkingProxyMain:: EventWriter could not be allocated"
);
enableCallStateLogObserver = false;
enableCallStateDbObserver = false;
}
}
// Do not exit, let the proxy do its stuff
while( !gShutdownFlag )
{
if( interactiveSet)
{
int charCode = getchar();
if(charCode != '\n' && charCode != '\r')
{
if( charCode == 'e')
{
OsSysLog::enableConsoleOutput(TRUE);
}
else if( charCode == 'd')
{
OsSysLog::enableConsoleOutput(FALSE);
}
#ifdef BOUNDS_CHECKER
else if( charCode == 'b')
{
NMMemPopup( );
}
#endif
else
{
sipUserAgent.printStatus();
sipUserAgent.getMessageLog(buffer);
printf("=================>\n%s\n", buffer.data());
}
}
}
else
OsTask::delay(2000);
}
// flush and close the call state event log
if (enableCallStateLogObserver || enableCallStateDbObserver)
{
if (cseObserver)
{
delete cseObserver;
}
if (pEventWriter)
{
delete pEventWriter;
}
}
// Flush the log file
OsSysLog::flush();
return(1);
}
syntax highlighted by Code2HTML, v. 0.9.1