// // // 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 #include #if defined(_WIN32) #include #elif defined(__pingtel_on_posix__) #include #endif #include #include #include #include #include #include #include #include #include #include #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\n\t\t"); \ APPEND_STRING.append(FROM_HOST); \ APPEND_STRING.append("\n\t\t"); \ APPEND_STRING.append(TO_HOST); \ APPEND_STRING.append("\n\t\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; iget(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/ 2) Else the path is assumed to be: ./ */ 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\"", // 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); }