2004-05-22 00:05:20 +00:00
|
|
|
/**
|
|
|
|
* Engine.cpp
|
|
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
2004-11-29 03:56:41 +00:00
|
|
|
*
|
|
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
2006-05-27 15:08:43 +00:00
|
|
|
* Copyright (C) 2004-2006 Null Team
|
2004-11-29 03:56:41 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2006-05-27 15:08:43 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
2004-05-22 00:05:20 +00:00
|
|
|
*/
|
|
|
|
|
2005-03-18 18:16:59 +00:00
|
|
|
#include "yatengine.h"
|
2004-12-01 15:01:30 +00:00
|
|
|
#include "yateversn.h"
|
2006-06-11 16:50:04 +00:00
|
|
|
|
2005-04-02 00:49:38 +00:00
|
|
|
#ifdef _WINDOWS
|
2006-06-11 16:50:04 +00:00
|
|
|
|
2005-04-02 00:49:38 +00:00
|
|
|
#include <process.h>
|
2006-06-11 20:12:05 +00:00
|
|
|
#include <shlobj.h>
|
2005-04-02 00:49:38 +00:00
|
|
|
#define RTLD_NOW 0
|
|
|
|
#define dlopen(name,flags) LoadLibrary(name)
|
|
|
|
#define dlclose !FreeLibrary
|
2008-01-24 21:09:41 +00:00
|
|
|
#define dlsym GetProcAddress
|
2005-04-02 00:49:38 +00:00
|
|
|
#define dlerror() "LoadLibrary error"
|
2005-05-20 23:08:16 +00:00
|
|
|
#define YSERV_RUN 1
|
|
|
|
#define YSERV_INS 2
|
|
|
|
#define YSERV_DEL 4
|
2005-05-24 15:09:19 +00:00
|
|
|
#define PATH_SEP "\\"
|
2008-07-25 18:00:04 +00:00
|
|
|
#ifndef CFG_DIR
|
2006-06-11 16:50:04 +00:00
|
|
|
#define CFG_DIR "Yate"
|
2008-07-25 18:00:04 +00:00
|
|
|
#endif
|
2006-06-11 16:50:04 +00:00
|
|
|
|
|
|
|
#ifndef SHGetSpecialFolderPath
|
|
|
|
__declspec(dllimport) BOOL WINAPI SHGetSpecialFolderPathA(HWND,LPSTR,INT,BOOL);
|
|
|
|
#endif
|
|
|
|
|
2005-04-02 00:49:38 +00:00
|
|
|
#else
|
2006-06-11 16:50:04 +00:00
|
|
|
|
2005-04-02 00:49:38 +00:00
|
|
|
#include "yatepaths.h"
|
2004-05-22 00:05:20 +00:00
|
|
|
#include <dirent.h>
|
2005-04-02 00:49:38 +00:00
|
|
|
#include <dlfcn.h>
|
|
|
|
#include <sys/wait.h>
|
2006-06-20 20:17:32 +00:00
|
|
|
#include <sys/resource.h>
|
2005-04-02 00:49:38 +00:00
|
|
|
typedef void* HMODULE;
|
2005-05-24 15:09:19 +00:00
|
|
|
#define PATH_SEP "/"
|
2008-07-25 18:00:04 +00:00
|
|
|
#ifndef CFG_DIR
|
2006-06-11 16:50:04 +00:00
|
|
|
#define CFG_DIR ".yate"
|
2008-07-25 18:00:04 +00:00
|
|
|
#endif
|
2006-06-11 16:50:04 +00:00
|
|
|
|
2005-04-02 00:49:38 +00:00
|
|
|
#endif
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
2009-06-22 11:09:38 +00:00
|
|
|
#ifdef HAVE_PRCTL
|
|
|
|
#include <sys/prctl.h>
|
|
|
|
#endif
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
namespace TelEngine {
|
|
|
|
|
|
|
|
class EnginePrivate : public Thread
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
EnginePrivate()
|
2009-06-22 14:48:26 +00:00
|
|
|
: Thread("Engine Worker")
|
2004-05-22 00:05:20 +00:00
|
|
|
{ count++; }
|
|
|
|
~EnginePrivate()
|
|
|
|
{ count--; }
|
|
|
|
virtual void run();
|
|
|
|
static int count;
|
|
|
|
};
|
|
|
|
|
2008-01-24 21:09:41 +00:00
|
|
|
class EngineCommand : public MessageHandler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
EngineCommand() : MessageHandler("engine.command") { }
|
|
|
|
virtual bool received(Message &msg);
|
|
|
|
static void doCompletion(Message &msg, const String& partLine, const String& partWord);
|
|
|
|
};
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
using namespace TelEngine;
|
|
|
|
|
|
|
|
#ifndef MOD_PATH
|
2005-05-24 15:09:19 +00:00
|
|
|
#define MOD_PATH "." PATH_SEP "modules"
|
2004-05-22 00:05:20 +00:00
|
|
|
#endif
|
2007-11-26 12:01:09 +00:00
|
|
|
#ifndef SHR_PATH
|
|
|
|
#define SHR_PATH "." PATH_SEP "share"
|
|
|
|
#endif
|
2004-05-22 00:05:20 +00:00
|
|
|
#ifndef CFG_PATH
|
2005-05-24 15:09:19 +00:00
|
|
|
#define CFG_PATH "." PATH_SEP "conf.d"
|
2004-05-22 00:05:20 +00:00
|
|
|
#endif
|
2010-01-27 16:44:19 +00:00
|
|
|
#ifndef DLL_SUFFIX
|
2004-05-22 00:05:20 +00:00
|
|
|
#define DLL_SUFFIX ".yate"
|
2010-01-27 16:44:19 +00:00
|
|
|
#endif
|
|
|
|
#ifndef CFG_SUFFIX
|
2004-05-22 00:05:20 +00:00
|
|
|
#define CFG_SUFFIX ".conf"
|
2010-01-27 16:44:19 +00:00
|
|
|
#endif
|
2004-05-22 00:05:20 +00:00
|
|
|
|
2010-06-16 09:05:08 +00:00
|
|
|
// Maximum number of engine.stop messages we allow
|
|
|
|
#ifndef MAX_STOP
|
|
|
|
#define MAX_STOP 5
|
|
|
|
#endif
|
2008-09-21 14:43:23 +00:00
|
|
|
|
|
|
|
// Supervisor control constants
|
|
|
|
|
|
|
|
// Maximum the child's sanity pool can grow
|
2005-04-23 19:33:37 +00:00
|
|
|
#define MAX_SANITY 5
|
2008-09-21 14:43:23 +00:00
|
|
|
// Initial sanity buffer, allow some init time for the child
|
2007-08-09 10:48:58 +00:00
|
|
|
#define INIT_SANITY 30
|
2008-09-21 14:43:23 +00:00
|
|
|
// Minimum (and initial) delay until supervisor restarts child
|
|
|
|
#define RUNDELAY_MIN 1000000
|
|
|
|
// Maximum delay until supervisor restarts child, allow system to breathe
|
|
|
|
#define RUNDELAY_MAX 60000000
|
|
|
|
// Amount we decerease delay towards minimum each time child proves sanity
|
|
|
|
#define RUNDELAY_DEC 20000
|
|
|
|
// Size of log relay buffer in bytes
|
2007-01-25 20:46:32 +00:00
|
|
|
#define MAX_LOGBUFF 4096
|
2004-10-21 13:50:45 +00:00
|
|
|
|
2008-01-19 11:19:52 +00:00
|
|
|
#ifndef HOST_NAME_MAX
|
|
|
|
#define HOST_NAME_MAX 255
|
|
|
|
#endif
|
|
|
|
|
2005-04-02 00:49:38 +00:00
|
|
|
static u_int64_t s_nextinit = 0;
|
|
|
|
static u_int64_t s_restarts = 0;
|
2004-05-22 00:05:20 +00:00
|
|
|
static bool s_makeworker = true;
|
|
|
|
static bool s_keepclosing = false;
|
2006-06-16 15:46:29 +00:00
|
|
|
static bool s_nounload = false;
|
2004-10-21 13:50:45 +00:00
|
|
|
static int s_super_handle = -1;
|
2010-01-07 12:11:09 +00:00
|
|
|
static int s_run_attempt = 0;
|
2010-01-27 12:07:51 +00:00
|
|
|
static bool s_interactive = true;
|
2006-05-27 14:53:18 +00:00
|
|
|
static bool s_localsymbol = false;
|
2009-02-26 16:26:55 +00:00
|
|
|
static bool s_logtruncate = false;
|
2010-01-27 12:07:51 +00:00
|
|
|
static const char* s_logfile = 0;
|
2004-05-22 00:05:20 +00:00
|
|
|
|
|
|
|
static void sighandler(int signal)
|
|
|
|
{
|
|
|
|
switch (signal) {
|
2005-04-02 00:49:38 +00:00
|
|
|
#ifndef _WINDOWS
|
2005-09-29 19:34:23 +00:00
|
|
|
case SIGCHLD:
|
|
|
|
::waitpid(-1,0,WNOHANG);
|
|
|
|
break;
|
|
|
|
case SIGUSR1:
|
|
|
|
Engine::restart(0,true);
|
|
|
|
break;
|
|
|
|
case SIGUSR2:
|
|
|
|
Engine::restart(0,false);
|
|
|
|
break;
|
2004-05-22 00:05:20 +00:00
|
|
|
case SIGHUP:
|
2010-01-27 12:07:51 +00:00
|
|
|
if (s_interactive) {
|
|
|
|
// console got closed so shutdown without writing to console
|
|
|
|
if (!s_logfile)
|
|
|
|
Debugger::enableOutput(false);
|
|
|
|
Engine::halt(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// intentionally fall through
|
2004-05-22 00:05:20 +00:00
|
|
|
case SIGQUIT:
|
|
|
|
if (s_nextinit <= Time::now())
|
|
|
|
Engine::init();
|
|
|
|
s_nextinit = Time::now() + 2000000;
|
|
|
|
break;
|
2005-04-02 00:49:38 +00:00
|
|
|
#endif
|
2004-05-22 00:05:20 +00:00
|
|
|
case SIGINT:
|
|
|
|
case SIGTERM:
|
|
|
|
Engine::halt(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-19 11:19:52 +00:00
|
|
|
String Engine::s_node;
|
2007-11-15 23:06:36 +00:00
|
|
|
String Engine::s_shrpath(SHR_PATH);
|
2004-05-22 00:05:20 +00:00
|
|
|
String Engine::s_cfgsuffix(CFG_SUFFIX);
|
|
|
|
String Engine::s_modpath(MOD_PATH);
|
|
|
|
String Engine::s_modsuffix(DLL_SUFFIX);
|
2007-07-23 16:18:18 +00:00
|
|
|
ObjList Engine::s_extramod;
|
2008-01-24 11:43:04 +00:00
|
|
|
NamedList Engine::s_params("");
|
2004-05-22 00:05:20 +00:00
|
|
|
|
2007-03-26 17:38:50 +00:00
|
|
|
Engine::RunMode Engine::s_mode = Engine::Stopped;
|
2005-03-20 03:11:53 +00:00
|
|
|
Engine* Engine::s_self = 0;
|
2004-05-22 00:05:20 +00:00
|
|
|
int Engine::s_haltcode = -1;
|
|
|
|
int EnginePrivate::count = 0;
|
2008-10-14 20:15:33 +00:00
|
|
|
static String s_cfgpath(CFG_PATH);
|
|
|
|
static String s_usrpath;
|
|
|
|
static bool s_createusr = true;
|
2006-06-10 12:05:16 +00:00
|
|
|
static bool s_init = false;
|
|
|
|
static bool s_dynplugin = false;
|
2007-11-26 23:56:37 +00:00
|
|
|
static Engine::PluginMode s_loadMode = Engine::LoadFail;
|
2006-06-10 12:05:16 +00:00
|
|
|
static int s_maxworkers = 10;
|
2006-06-10 12:33:16 +00:00
|
|
|
static bool s_debug = true;
|
2004-05-22 00:05:20 +00:00
|
|
|
|
2008-03-10 15:40:54 +00:00
|
|
|
#ifdef RLIMIT_CORE
|
2006-06-20 20:17:32 +00:00
|
|
|
static bool s_coredump = false;
|
2008-03-10 15:40:54 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef RLIMIT_NOFILE
|
|
|
|
#ifdef FDSIZE_HACK
|
|
|
|
static bool s_numfiles = false;
|
|
|
|
#else
|
|
|
|
#undef RLIMIT_NOFILE
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2005-05-20 23:14:11 +00:00
|
|
|
static bool s_sigabrt = false;
|
2006-07-17 13:33:02 +00:00
|
|
|
static bool s_lateabrt = false;
|
2006-06-12 12:16:29 +00:00
|
|
|
static String s_cfgfile;
|
2008-10-14 20:15:33 +00:00
|
|
|
static String s_userdir(CFG_DIR);
|
2005-11-26 18:26:46 +00:00
|
|
|
static Configuration s_cfg;
|
|
|
|
static ObjList plugins;
|
|
|
|
static ObjList* s_cmds = 0;
|
|
|
|
static unsigned int s_runid = 0;
|
2004-05-22 00:05:20 +00:00
|
|
|
|
2009-04-02 14:35:51 +00:00
|
|
|
static EngineCheck* s_engineCheck = 0;
|
|
|
|
|
|
|
|
void EngineCheck::setChecker(EngineCheck* ptr)
|
|
|
|
{
|
|
|
|
s_engineCheck = ptr;
|
|
|
|
}
|
|
|
|
|
2008-01-24 21:09:41 +00:00
|
|
|
class SLib : public String
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual ~SLib();
|
2009-06-18 17:44:48 +00:00
|
|
|
static SLib* load(const char* file, bool local, bool nounload);
|
2008-01-24 21:09:41 +00:00
|
|
|
bool unload(bool doNow);
|
2004-05-22 00:05:20 +00:00
|
|
|
private:
|
2009-06-18 17:44:48 +00:00
|
|
|
SLib(HMODULE handle, const char* file, bool nounload);
|
2005-04-02 00:49:38 +00:00
|
|
|
HMODULE m_handle;
|
2009-06-18 17:44:48 +00:00
|
|
|
bool m_nounload;
|
2004-05-22 00:05:20 +00:00
|
|
|
};
|
|
|
|
|
2004-10-21 13:50:45 +00:00
|
|
|
class EngineSuperHandler : public MessageHandler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
EngineSuperHandler() : MessageHandler("engine.timer",0), m_seq(0) { }
|
|
|
|
virtual bool received(Message &msg)
|
|
|
|
{ ::write(s_super_handle,&m_seq,1); m_seq++; return false; }
|
|
|
|
char m_seq;
|
|
|
|
};
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
class EngineStatusHandler : public MessageHandler
|
|
|
|
{
|
|
|
|
public:
|
2004-12-21 04:16:09 +00:00
|
|
|
EngineStatusHandler() : MessageHandler("engine.status",0) { }
|
2004-05-22 00:05:20 +00:00
|
|
|
virtual bool received(Message &msg);
|
|
|
|
};
|
|
|
|
|
2008-01-24 21:09:41 +00:00
|
|
|
class EngineHelp : public MessageHandler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
EngineHelp() : MessageHandler("engine.help") { }
|
|
|
|
virtual bool received(Message &msg);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-10-14 20:15:33 +00:00
|
|
|
// helper function to initialize user application data dir
|
|
|
|
static void initUsrPath(String& path, const char* newPath = 0)
|
|
|
|
{
|
|
|
|
if (path)
|
|
|
|
return;
|
|
|
|
if (TelEngine::null(newPath)) {
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
// we force using the ANSI version
|
|
|
|
char szPath[MAX_PATH];
|
|
|
|
if (SHGetSpecialFolderPathA(NULL,szPath,CSIDL_APPDATA,TRUE))
|
|
|
|
path = szPath;
|
|
|
|
#else
|
|
|
|
path = ::getenv("HOME");
|
|
|
|
#endif
|
|
|
|
if (path.null()) {
|
2009-07-14 15:49:20 +00:00
|
|
|
if (Engine::mode() == Engine::Client)
|
2008-10-19 16:28:54 +00:00
|
|
|
Debug(DebugWarn,"Could not get per-user application data path!");
|
|
|
|
path = s_cfgpath;
|
2008-10-14 20:15:33 +00:00
|
|
|
}
|
|
|
|
if (!path.endsWith(PATH_SEP))
|
|
|
|
path += PATH_SEP;
|
|
|
|
path += s_userdir;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
path = newPath;
|
|
|
|
if (path.endsWith(PATH_SEP))
|
|
|
|
path = path.substr(0,path.length()-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
bool EngineStatusHandler::received(Message &msg)
|
|
|
|
{
|
|
|
|
const char *sel = msg.getValue("module");
|
|
|
|
if (sel && ::strcmp(sel,"engine"))
|
|
|
|
return false;
|
2004-12-01 14:25:30 +00:00
|
|
|
msg.retValue() << "name=engine,type=system";
|
2005-06-13 12:08:56 +00:00
|
|
|
msg.retValue() << ",version=" << YATE_VERSION;
|
2010-05-28 17:07:49 +00:00
|
|
|
msg.retValue() << ",nodename=" << Engine::nodeName();
|
2004-12-01 14:25:30 +00:00
|
|
|
msg.retValue() << ";plugins=" << plugins.count();
|
2004-11-01 00:07:00 +00:00
|
|
|
msg.retValue() << ",inuse=" << Engine::self()->usedPlugins();
|
2005-06-07 16:12:25 +00:00
|
|
|
msg.retValue() << ",handlers=" << Engine::self()->handlerCount();
|
|
|
|
msg.retValue() << ",messages=" << Engine::self()->messageCount();
|
2005-04-14 03:14:20 +00:00
|
|
|
msg.retValue() << ",supervised=" << (s_super_handle >= 0);
|
2010-01-07 12:11:09 +00:00
|
|
|
msg.retValue() << ",runattempt=" << s_run_attempt;
|
2004-09-29 00:15:52 +00:00
|
|
|
msg.retValue() << ",threads=" << Thread::count();
|
2004-05-22 00:05:20 +00:00
|
|
|
msg.retValue() << ",workers=" << EnginePrivate::count;
|
2004-10-14 15:47:50 +00:00
|
|
|
msg.retValue() << ",mutexes=" << Mutex::count();
|
|
|
|
msg.retValue() << ",locks=" << Mutex::locks();
|
2009-07-22 12:57:14 +00:00
|
|
|
msg.retValue() << ",semaphores=" << Semaphore::count();
|
|
|
|
msg.retValue() << ",waiting=" << Semaphore::locks();
|
2006-11-02 19:53:44 +00:00
|
|
|
msg.retValue() << "\r\n";
|
2004-05-22 00:05:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-01-26 17:29:05 +00:00
|
|
|
static char s_cmdsOpt[] = " module {{load|reload} modulefile|unload modulename|list}\r\n";
|
2008-01-24 21:09:41 +00:00
|
|
|
static char s_cmdsMsg[] = "Controls the modules loaded in the Telephony Engine\r\n";
|
|
|
|
|
2008-10-14 20:15:33 +00:00
|
|
|
// get the base name of a module file
|
2008-01-26 17:29:05 +00:00
|
|
|
static String moduleBase(const String& fname)
|
|
|
|
{
|
|
|
|
int sep = fname.rfind(PATH_SEP[0]);
|
|
|
|
if (sep >= 0)
|
|
|
|
sep++;
|
|
|
|
else
|
|
|
|
sep = 0;
|
|
|
|
int len = fname.length() - sep;
|
|
|
|
if (fname.endsWith(Engine::moduleSuffix()))
|
|
|
|
len -= Engine::moduleSuffix().length();
|
|
|
|
return fname.substr(sep,len);
|
|
|
|
}
|
|
|
|
|
2008-01-24 21:09:41 +00:00
|
|
|
// perform one completion only if match still possible
|
|
|
|
static void completeOne(String& ret, const String& str, const char* part)
|
|
|
|
{
|
|
|
|
if (part && !str.startsWith(part))
|
|
|
|
return;
|
|
|
|
ret.append(str,"\t");
|
|
|
|
}
|
|
|
|
|
2008-01-26 17:29:05 +00:00
|
|
|
static void completeOneModule(String& ret, const String& str, const char* part, ObjList& mods, bool reload)
|
|
|
|
{
|
|
|
|
SLib* s = static_cast<SLib*>(mods[moduleBase(str)]);
|
|
|
|
if (s) {
|
|
|
|
if (!(reload && s->unload(false)))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (reload)
|
|
|
|
return;
|
|
|
|
completeOne(ret,str,part);
|
|
|
|
}
|
|
|
|
|
2008-01-24 21:09:41 +00:00
|
|
|
// complete a module filename from filesystem
|
2008-01-26 17:29:05 +00:00
|
|
|
void completeModule(String& ret, const String& part, ObjList& mods, bool reload, const String& rpath = String::empty())
|
2008-01-24 21:09:41 +00:00
|
|
|
{
|
|
|
|
if (part[0] == '.')
|
|
|
|
return;
|
|
|
|
String path = Engine::modulePath();
|
|
|
|
String rdir = rpath;
|
|
|
|
int sep = part.rfind(PATH_SEP[0]);
|
|
|
|
if (sep >= 0)
|
|
|
|
rdir += part.substr(0,sep+1);
|
|
|
|
if (rdir) {
|
|
|
|
if (!path.endsWith(PATH_SEP))
|
|
|
|
path += PATH_SEP;
|
|
|
|
path += rdir;
|
|
|
|
}
|
|
|
|
if (path.endsWith(PATH_SEP))
|
|
|
|
path = path.substr(0,path.length()-1);
|
|
|
|
|
|
|
|
DDebug(DebugInfo,"completeModule path='%s' rdir='%s'",path.c_str(),rdir.c_str());
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
WIN32_FIND_DATA entry;
|
|
|
|
HANDLE hf = ::FindFirstFile(path + PATH_SEP "*",&entry);
|
|
|
|
if (hf == INVALID_HANDLE_VALUE)
|
|
|
|
return;
|
|
|
|
do {
|
|
|
|
XDebug(DebugInfo,"Found dir entry %s",entry.cFileName);
|
2008-01-24 22:59:37 +00:00
|
|
|
if (entry.cFileName[0] == '.')
|
|
|
|
continue;
|
2008-01-24 21:09:41 +00:00
|
|
|
if ((entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)
|
|
|
|
continue;
|
|
|
|
if ((entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
|
2008-01-26 17:29:05 +00:00
|
|
|
completeModule(ret,part,mods,reload,rdir + entry.cFileName + PATH_SEP);
|
2008-01-24 21:09:41 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int n = ::strlen(entry.cFileName) - Engine::moduleSuffix().length();
|
|
|
|
if ((n > 0) && !::strcmp(entry.cFileName+n,Engine::moduleSuffix()))
|
2008-01-26 17:29:05 +00:00
|
|
|
completeOneModule(ret,rdir + entry.cFileName,part,mods,reload);
|
2008-01-24 21:09:41 +00:00
|
|
|
} while (::FindNextFile(hf,&entry));
|
|
|
|
::FindClose(hf);
|
|
|
|
#else
|
|
|
|
DIR *dir = ::opendir(path);
|
|
|
|
if (!dir)
|
|
|
|
return;
|
|
|
|
struct dirent* entry;
|
|
|
|
while ((entry = ::readdir(dir)) != 0) {
|
|
|
|
XDebug(DebugInfo,"Found dir entry %s",entry->d_name);
|
|
|
|
if (entry->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
struct stat stat_buf;
|
|
|
|
if (::stat(path + PATH_SEP + entry->d_name,&stat_buf))
|
|
|
|
continue;
|
|
|
|
if (S_ISDIR(stat_buf.st_mode)) {
|
2008-01-26 17:29:05 +00:00
|
|
|
completeModule(ret,part,mods,reload,rdir + entry->d_name + PATH_SEP);
|
2008-01-24 21:09:41 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int n = ::strlen(entry->d_name) - Engine::moduleSuffix().length();
|
|
|
|
if ((n > 0) && !::strcmp(entry->d_name+n,Engine::moduleSuffix()))
|
2008-01-26 17:29:05 +00:00
|
|
|
completeOneModule(ret,rdir + entry->d_name,part,mods,reload);
|
2008-01-24 21:09:41 +00:00
|
|
|
}
|
|
|
|
::closedir(dir);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// perform command line completion
|
|
|
|
void EngineCommand::doCompletion(Message &msg, const String& partLine, const String& partWord)
|
|
|
|
{
|
2008-01-25 18:19:03 +00:00
|
|
|
if (partLine.null() || (partLine == "help"))
|
2008-01-24 21:09:41 +00:00
|
|
|
completeOne(msg.retValue(),"module",partWord);
|
2008-01-25 18:19:03 +00:00
|
|
|
else if (partLine == "status")
|
|
|
|
completeOne(msg.retValue(),"engine",partWord);
|
2008-01-24 21:09:41 +00:00
|
|
|
else if (partLine == "module") {
|
|
|
|
completeOne(msg.retValue(),"load",partWord);
|
|
|
|
completeOne(msg.retValue(),"unload",partWord);
|
2008-01-26 17:29:05 +00:00
|
|
|
completeOne(msg.retValue(),"reload",partWord);
|
2008-01-24 21:09:41 +00:00
|
|
|
completeOne(msg.retValue(),"list",partWord);
|
|
|
|
}
|
|
|
|
else if (partLine == "module load")
|
2008-01-26 17:29:05 +00:00
|
|
|
completeModule(msg.retValue(),partWord,Engine::self()->m_libs,false);
|
|
|
|
else if (partLine == "module reload")
|
|
|
|
completeModule(msg.retValue(),partWord,Engine::self()->m_libs,true);
|
2008-01-24 21:09:41 +00:00
|
|
|
else if (partLine == "module unload") {
|
|
|
|
for (ObjList* l = Engine::self()->m_libs.skipNull();l;l = l->skipNext()) {
|
|
|
|
SLib* s = static_cast<SLib*>(l->get());
|
|
|
|
if (s->unload(false))
|
|
|
|
completeOne(msg.retValue(),*s,partWord);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EngineCommand::received(Message &msg)
|
|
|
|
{
|
|
|
|
String line = msg.getValue("line");
|
|
|
|
if (line.null()) {
|
|
|
|
doCompletion(msg,msg.getValue("partline"),msg.getValue("partword"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!line.startSkip("module"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool ok = false;
|
|
|
|
int sep = line.find(' ');
|
|
|
|
if (sep > 0) {
|
|
|
|
String cmd = line.substr(0,sep).trimBlanks();
|
|
|
|
String arg = line.substr(sep+1).trimBlanks();
|
2008-01-26 17:29:05 +00:00
|
|
|
if ((cmd == "load") || (cmd == "reload")) {
|
|
|
|
bool reload = (cmd == "reload");
|
|
|
|
cmd = moduleBase(arg);
|
|
|
|
SLib* s = static_cast<SLib*>(Engine::self()->m_libs[cmd]);
|
|
|
|
if (s) {
|
2008-01-24 21:09:41 +00:00
|
|
|
ok = true;
|
2008-01-26 17:29:05 +00:00
|
|
|
if (reload) {
|
|
|
|
if (s->unload(true)) {
|
|
|
|
Engine::self()->m_libs.remove(s);
|
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
msg.retValue() = "Module not unloaded: " + arg + "\r\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
msg.retValue() = "Module is already loaded: " + cmd + "\r\n";
|
2008-01-24 21:09:41 +00:00
|
|
|
}
|
2008-01-26 17:29:05 +00:00
|
|
|
if (!ok) {
|
2008-01-24 21:09:41 +00:00
|
|
|
ok = Engine::self()->loadPlugin(Engine::modulePath() + PATH_SEP + arg);
|
|
|
|
// if we loaded it successfully we must initialize
|
|
|
|
if (ok)
|
|
|
|
Engine::self()->initPlugins();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (cmd == "unload") {
|
|
|
|
SLib* s = static_cast<SLib*>(Engine::self()->m_libs[arg]);
|
|
|
|
if (!s)
|
|
|
|
msg.retValue() = "Module not loaded: " + arg + "\r\n";
|
|
|
|
else if (s->unload(true)) {
|
|
|
|
Engine::self()->m_libs.remove(s);
|
|
|
|
msg.retValue() = "Unloaded module: " + arg + "\r\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
msg.retValue() = "Could not unload module: " + arg + "\r\n";
|
|
|
|
ok = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (line == "list") {
|
|
|
|
msg.retValue().clear();
|
|
|
|
for (ObjList* l = Engine::self()->m_libs.skipNull();l;l = l->skipNext()) {
|
|
|
|
SLib* s = static_cast<SLib*>(l->get());
|
|
|
|
msg.retValue().append(*s,"\t");
|
2008-01-26 17:33:42 +00:00
|
|
|
if (s->unload(false))
|
|
|
|
msg.retValue() += "*";
|
2008-01-24 21:09:41 +00:00
|
|
|
}
|
|
|
|
msg.retValue() << "\r\n";
|
|
|
|
ok = true;
|
|
|
|
}
|
|
|
|
if (!ok)
|
|
|
|
msg.retValue() = "Module operation failed: " + line + "\r\n";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool EngineHelp::received(Message &msg)
|
|
|
|
{
|
|
|
|
String line = msg.getValue("line");
|
|
|
|
if (line.null()) {
|
|
|
|
msg.retValue() << s_cmdsOpt;
|
|
|
|
return false;
|
|
|
|
}
|
2008-01-25 18:19:03 +00:00
|
|
|
if (line != "module")
|
2008-01-24 21:09:41 +00:00
|
|
|
return false;
|
|
|
|
msg.retValue() << s_cmdsOpt << s_cmdsMsg;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
void EnginePrivate::run()
|
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
s_makeworker = false;
|
|
|
|
Engine::self()->m_dispatcher.dequeue();
|
2009-06-24 16:47:29 +00:00
|
|
|
Thread::idle(true);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-24 21:09:41 +00:00
|
|
|
|
2005-05-24 15:09:19 +00:00
|
|
|
static bool logFileOpen()
|
|
|
|
{
|
|
|
|
if (s_logfile) {
|
2010-10-11 11:00:35 +00:00
|
|
|
int flags = O_WRONLY|O_CREAT|O_LARGEFILE;
|
2009-02-26 16:26:55 +00:00
|
|
|
if (s_logtruncate) {
|
|
|
|
s_logtruncate = false;
|
|
|
|
flags |= O_TRUNC;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
flags |= O_APPEND;
|
|
|
|
int fd = ::open(s_logfile,flags,0640);
|
2005-05-24 15:09:19 +00:00
|
|
|
if (fd >= 0) {
|
|
|
|
// Redirect stdout and stderr to the new file
|
|
|
|
::fflush(stdout);
|
|
|
|
::dup2(fd,1);
|
|
|
|
::fflush(stderr);
|
|
|
|
::dup2(fd,2);
|
|
|
|
::close(fd);
|
|
|
|
Debugger::enableOutput(true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-05-20 23:08:16 +00:00
|
|
|
static int engineRun()
|
|
|
|
{
|
|
|
|
time_t t = ::time(0);
|
|
|
|
Output("Yate (%u) is starting %s",::getpid(),::ctime(&t));
|
|
|
|
int retcode = Engine::self()->run();
|
|
|
|
t = ::time(0);
|
|
|
|
Output("Yate (%u) is stopping %s",::getpid(),::ctime(&t));
|
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
|
|
|
|
static SERVICE_STATUS_HANDLE s_handler = 0;
|
|
|
|
static SERVICE_STATUS s_status;
|
|
|
|
|
|
|
|
static void setStatus(DWORD state)
|
|
|
|
{
|
|
|
|
if (!s_handler)
|
|
|
|
return;
|
2005-06-02 09:29:09 +00:00
|
|
|
switch (state) {
|
|
|
|
case SERVICE_START_PENDING:
|
|
|
|
case SERVICE_STOP_PENDING:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
s_status.dwCheckPoint = 0;
|
|
|
|
}
|
2005-05-20 23:08:16 +00:00
|
|
|
s_status.dwCurrentState = state;
|
2005-06-02 09:29:09 +00:00
|
|
|
::SetServiceStatus(s_handler,&s_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void checkPoint()
|
|
|
|
{
|
|
|
|
if (!s_handler)
|
|
|
|
return;
|
|
|
|
s_status.dwCheckPoint++;
|
|
|
|
::SetServiceStatus(s_handler,&s_status);
|
2005-05-20 23:08:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void WINAPI serviceHandler(DWORD code)
|
|
|
|
{
|
|
|
|
switch (code) {
|
|
|
|
case SERVICE_CONTROL_STOP:
|
2005-06-02 09:29:09 +00:00
|
|
|
case SERVICE_CONTROL_SHUTDOWN:
|
2005-05-20 23:08:16 +00:00
|
|
|
Engine::halt(0);
|
2005-06-02 09:29:09 +00:00
|
|
|
setStatus(SERVICE_STOP_PENDING);
|
2005-05-20 23:08:16 +00:00
|
|
|
break;
|
|
|
|
case SERVICE_CONTROL_PARAMCHANGE:
|
|
|
|
Engine::init();
|
|
|
|
break;
|
2005-06-02 09:29:09 +00:00
|
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
|
|
break;
|
2005-05-20 23:08:16 +00:00
|
|
|
default:
|
|
|
|
Debug(DebugWarn,"Got unexpected service control code %u",code);
|
|
|
|
}
|
2005-06-02 09:29:09 +00:00
|
|
|
if (s_handler)
|
|
|
|
::SetServiceStatus(s_handler,&s_status);
|
2005-05-20 23:08:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void serviceMain(DWORD argc, LPTSTR* argv)
|
|
|
|
{
|
2005-05-24 15:09:19 +00:00
|
|
|
logFileOpen();
|
2005-05-20 23:08:16 +00:00
|
|
|
s_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
|
|
s_status.dwCurrentState = SERVICE_START_PENDING;
|
|
|
|
s_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PARAMCHANGE;
|
|
|
|
s_status.dwWin32ExitCode = NO_ERROR;
|
|
|
|
s_status.dwServiceSpecificExitCode = 0;
|
|
|
|
s_status.dwCheckPoint = 0;
|
|
|
|
s_status.dwWaitHint = 0;
|
2005-06-02 09:29:09 +00:00
|
|
|
s_handler = ::RegisterServiceCtrlHandler("yate",serviceHandler);
|
2005-05-20 23:08:16 +00:00
|
|
|
if (!s_handler) {
|
2006-11-02 19:53:44 +00:00
|
|
|
Debug(DebugFail,"Could not register service control handler \"yate\", code %u",::GetLastError());
|
2005-05-20 23:08:16 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
setStatus(SERVICE_START_PENDING);
|
|
|
|
engineRun();
|
|
|
|
}
|
|
|
|
|
|
|
|
static SERVICE_TABLE_ENTRY dispatchTable[] =
|
|
|
|
{
|
|
|
|
{ TEXT("yate"), (LPSERVICE_MAIN_FUNCTION)serviceMain },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
#else /* _WINDOWS */
|
|
|
|
|
|
|
|
#define setStatus(s)
|
2005-06-02 09:29:09 +00:00
|
|
|
#define checkPoint()
|
2005-05-20 23:08:16 +00:00
|
|
|
|
2007-01-25 20:46:32 +00:00
|
|
|
static bool s_logrotator = false;
|
2008-05-01 14:01:53 +00:00
|
|
|
static volatile bool s_rotatenow = false;
|
|
|
|
static volatile bool s_runagain = true;
|
2008-09-21 14:43:23 +00:00
|
|
|
static unsigned int s_rundelay = RUNDELAY_MIN;
|
2005-05-20 23:08:16 +00:00
|
|
|
static pid_t s_childpid = -1;
|
2007-01-25 20:46:32 +00:00
|
|
|
static pid_t s_superpid = -1;
|
2005-05-20 23:08:16 +00:00
|
|
|
|
|
|
|
static void superhandler(int signal)
|
|
|
|
{
|
|
|
|
switch (signal) {
|
2010-01-16 20:40:03 +00:00
|
|
|
case SIGUSR1:
|
|
|
|
case SIGUSR2:
|
|
|
|
s_rundelay = RUNDELAY_MIN;
|
|
|
|
break;
|
2007-01-25 20:46:32 +00:00
|
|
|
case SIGHUP:
|
2010-01-27 12:07:51 +00:00
|
|
|
if (!s_interactive) {
|
|
|
|
if (s_logrotator)
|
|
|
|
s_rotatenow = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// intentionally fall through
|
2005-05-20 23:08:16 +00:00
|
|
|
case SIGINT:
|
|
|
|
case SIGTERM:
|
|
|
|
case SIGABRT:
|
|
|
|
s_runagain = false;
|
|
|
|
}
|
|
|
|
if (s_childpid > 0)
|
|
|
|
::kill(s_childpid,signal);
|
|
|
|
}
|
|
|
|
|
2008-05-01 14:01:53 +00:00
|
|
|
static void rotatelogs()
|
|
|
|
{
|
|
|
|
if (s_rotatenow) {
|
|
|
|
s_rotatenow = false;
|
|
|
|
::fprintf(stderr,"Supervisor (%d) closing the log file\n",s_superpid);
|
|
|
|
logFileOpen();
|
|
|
|
::fprintf(stderr,"Supervisor (%d) reopening the log file\n",s_superpid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-25 20:46:32 +00:00
|
|
|
static void copystream(int dest, int src)
|
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
char buf[MAX_LOGBUFF];
|
|
|
|
int rd = ::read(src,buf,sizeof(buf));
|
|
|
|
if (rd <= 0)
|
|
|
|
break;
|
|
|
|
::write(dest,buf,rd);
|
|
|
|
}
|
2008-05-01 14:01:53 +00:00
|
|
|
rotatelogs();
|
2007-01-25 20:46:32 +00:00
|
|
|
}
|
|
|
|
|
2005-05-20 23:08:16 +00:00
|
|
|
static int supervise(void)
|
|
|
|
{
|
2007-01-25 20:46:32 +00:00
|
|
|
s_superpid = ::getpid();
|
|
|
|
::fprintf(stderr,"Supervisor (%u) is starting\n",s_superpid);
|
2005-05-20 23:08:16 +00:00
|
|
|
::signal(SIGINT,superhandler);
|
|
|
|
::signal(SIGTERM,superhandler);
|
|
|
|
::signal(SIGHUP,superhandler);
|
|
|
|
::signal(SIGQUIT,superhandler);
|
|
|
|
::signal(SIGABRT,superhandler);
|
2005-09-29 19:34:23 +00:00
|
|
|
::signal(SIGUSR1,superhandler);
|
|
|
|
::signal(SIGUSR2,superhandler);
|
2005-05-20 23:08:16 +00:00
|
|
|
int retcode = 0;
|
|
|
|
while (s_runagain) {
|
|
|
|
int wdogfd[2];
|
|
|
|
if (::pipe(wdogfd)) {
|
|
|
|
int err = errno;
|
2007-01-25 20:46:32 +00:00
|
|
|
::fprintf(stderr,"Supervisor: watchdog pipe failed: %s (%d)\n",::strerror(err),err);
|
2005-05-20 23:08:16 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
::fcntl(wdogfd[0],F_SETFL,O_NONBLOCK);
|
|
|
|
::fcntl(wdogfd[1],F_SETFL,O_NONBLOCK);
|
2007-01-25 20:46:32 +00:00
|
|
|
int logfd[2] = { -1, -1 };
|
|
|
|
if (s_logrotator) {
|
|
|
|
if (::pipe(logfd)) {
|
|
|
|
int err = errno;
|
|
|
|
::fprintf(stderr,"Supervisor: log pipe failed: %s (%d)\n",::strerror(err),err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
::fcntl(logfd[0],F_SETFL,O_NONBLOCK);
|
|
|
|
}
|
2007-08-09 10:48:58 +00:00
|
|
|
// reap any children we may have before spawning a new one
|
2007-08-15 12:28:57 +00:00
|
|
|
while (::waitpid(-1,0,WNOHANG) > 0)
|
|
|
|
;
|
2008-05-01 14:01:53 +00:00
|
|
|
rotatelogs();
|
2010-01-07 12:11:09 +00:00
|
|
|
s_run_attempt++;
|
2005-05-20 23:08:16 +00:00
|
|
|
s_childpid = ::fork();
|
|
|
|
if (s_childpid < 0) {
|
|
|
|
int err = errno;
|
|
|
|
::fprintf(stderr,"Supervisor: fork failed: %s (%d)\n",::strerror(err),err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
if (s_childpid == 0) {
|
|
|
|
s_super_handle = wdogfd[1];
|
|
|
|
::close(wdogfd[0]);
|
2007-01-25 20:46:32 +00:00
|
|
|
if (s_logrotator) {
|
|
|
|
::close(logfd[0]);
|
|
|
|
// Redirect stdout and stderr to the new file
|
|
|
|
::fflush(stdout);
|
|
|
|
::dup2(logfd[1],1);
|
|
|
|
::fflush(stderr);
|
|
|
|
::dup2(logfd[1],2);
|
|
|
|
::close(logfd[1]);
|
|
|
|
}
|
2005-05-20 23:08:16 +00:00
|
|
|
::signal(SIGINT,SIG_DFL);
|
|
|
|
::signal(SIGTERM,SIG_DFL);
|
|
|
|
::signal(SIGHUP,SIG_DFL);
|
|
|
|
::signal(SIGQUIT,SIG_DFL);
|
|
|
|
::signal(SIGABRT,SIG_DFL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
::close(wdogfd[1]);
|
2007-01-25 20:46:32 +00:00
|
|
|
if (s_logrotator)
|
|
|
|
::close(logfd[1]);
|
2005-05-20 23:08:16 +00:00
|
|
|
// Wait for the child to die or block
|
|
|
|
for (int sanity = INIT_SANITY; sanity > 0; sanity--) {
|
|
|
|
int status = -1;
|
|
|
|
int tmp = ::waitpid(s_childpid,&status,WNOHANG);
|
|
|
|
if (tmp > 0) {
|
|
|
|
// Child exited for some reason
|
|
|
|
if (WIFEXITED(status)) {
|
|
|
|
retcode = WEXITSTATUS(status);
|
2010-06-16 08:35:42 +00:00
|
|
|
::fprintf(stderr,"Supervisor: child %d exited with code %d\n",s_childpid,retcode);
|
2005-05-20 23:08:16 +00:00
|
|
|
if (retcode <= 127)
|
|
|
|
s_runagain = false;
|
|
|
|
else
|
|
|
|
retcode &= 127;
|
|
|
|
}
|
|
|
|
else if (WIFSIGNALED(status)) {
|
|
|
|
retcode = WTERMSIG(status);
|
|
|
|
::fprintf(stderr,"Supervisor: child %d died on signal %d\n",s_childpid,retcode);
|
|
|
|
}
|
|
|
|
s_childpid = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
char buf[MAX_SANITY];
|
|
|
|
tmp = ::read(wdogfd[0],buf,sizeof(buf));
|
|
|
|
if (tmp >= 0) {
|
|
|
|
// Timer messages add one sanity point every second
|
2007-03-26 15:07:42 +00:00
|
|
|
tmp += sanity;
|
|
|
|
if (tmp > MAX_SANITY)
|
|
|
|
tmp = MAX_SANITY;
|
|
|
|
if (sanity < tmp)
|
|
|
|
sanity = tmp;
|
2008-09-21 14:43:23 +00:00
|
|
|
// Decrement inter-run delay each time child proves sanity
|
|
|
|
s_rundelay -= RUNDELAY_DEC;
|
|
|
|
if (s_rundelay < RUNDELAY_MIN)
|
|
|
|
s_rundelay = RUNDELAY_MIN;
|
2005-05-20 23:08:16 +00:00
|
|
|
}
|
|
|
|
else if ((errno != EINTR) && (errno != EAGAIN))
|
|
|
|
break;
|
|
|
|
// Consume sanity points slightly slower than added
|
2007-03-26 15:07:42 +00:00
|
|
|
for (int i = 0; i < 12; i++) {
|
2008-05-01 14:01:53 +00:00
|
|
|
if (s_logrotator)
|
|
|
|
copystream(2,logfd[0]);
|
2007-03-26 15:07:42 +00:00
|
|
|
::usleep(100000);
|
2007-01-25 20:46:32 +00:00
|
|
|
}
|
2005-05-20 23:08:16 +00:00
|
|
|
}
|
|
|
|
::close(wdogfd[0]);
|
|
|
|
if (s_childpid > 0) {
|
|
|
|
// Child failed to proof sanity. Kill it - no need to be gentle.
|
|
|
|
::fprintf(stderr,"Supervisor: killing unresponsive child %d\n",s_childpid);
|
2010-06-16 08:35:42 +00:00
|
|
|
#ifdef RLIMIT_CORE
|
|
|
|
// If -Da or -C were specified try to get a corefile
|
|
|
|
if (s_sigabrt || s_coredump) {
|
|
|
|
#else
|
2005-05-20 23:08:16 +00:00
|
|
|
// If -Da was specified try to get a corefile
|
|
|
|
if (s_sigabrt) {
|
2010-06-16 08:35:42 +00:00
|
|
|
#endif
|
2005-05-20 23:08:16 +00:00
|
|
|
::kill(s_childpid,SIGABRT);
|
2007-03-26 15:07:42 +00:00
|
|
|
::usleep(500000);
|
2005-05-20 23:08:16 +00:00
|
|
|
}
|
2008-06-24 16:44:16 +00:00
|
|
|
// Try to kill until it dies or we get a termination signal
|
|
|
|
while ((s_childpid > 0) && !::kill(s_childpid,SIGKILL)) {
|
|
|
|
if (!s_runagain)
|
|
|
|
break;
|
|
|
|
::usleep(100000);
|
|
|
|
int status = -1;
|
|
|
|
if (::waitpid(s_childpid,&status,WNOHANG) > 0)
|
|
|
|
break;
|
|
|
|
}
|
2005-05-20 23:08:16 +00:00
|
|
|
s_childpid = -1;
|
|
|
|
}
|
2007-01-25 20:46:32 +00:00
|
|
|
if (s_logrotator) {
|
|
|
|
copystream(2,logfd[0]);
|
|
|
|
::close(logfd[0]);
|
|
|
|
}
|
2008-09-21 14:43:23 +00:00
|
|
|
if (s_runagain) {
|
|
|
|
if (s_rundelay > RUNDELAY_MIN)
|
|
|
|
::fprintf(stderr,"Supervisor (%d) delaying child start by %u.%02u seconds\n",
|
|
|
|
s_superpid,s_rundelay / 1000000,(s_rundelay / 10000) % 100);
|
|
|
|
::usleep(s_rundelay);
|
|
|
|
// Exponential backoff, double run delay each time we restart child
|
|
|
|
s_rundelay *= 2;
|
|
|
|
if (s_rundelay > RUNDELAY_MAX)
|
|
|
|
s_rundelay = RUNDELAY_MAX;
|
|
|
|
}
|
2005-05-20 23:08:16 +00:00
|
|
|
}
|
2007-01-25 20:46:32 +00:00
|
|
|
::fprintf(stderr,"Supervisor (%d) exiting with code %d\n",s_superpid,retcode);
|
2005-05-20 23:08:16 +00:00
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
#endif /* _WINDOWS */
|
|
|
|
|
2007-11-26 23:56:37 +00:00
|
|
|
|
2009-06-18 17:44:48 +00:00
|
|
|
SLib::SLib(HMODULE handle, const char* file, bool nounload)
|
|
|
|
: String(moduleBase(file)), m_handle(handle), m_nounload(nounload)
|
2005-06-02 09:29:09 +00:00
|
|
|
{
|
2009-06-18 17:44:48 +00:00
|
|
|
DDebug(DebugAll,"SLib::SLib(%p,'%s',%s) [%p]",
|
|
|
|
handle,file,String::boolText(nounload),this);
|
2005-06-02 09:29:09 +00:00
|
|
|
checkPoint();
|
|
|
|
}
|
|
|
|
|
|
|
|
SLib::~SLib()
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
2010-01-30 20:33:11 +00:00
|
|
|
Debugger debug("SLib::~SLib()"," '%s' [%p]",c_str(),this);
|
2005-06-02 09:29:09 +00:00
|
|
|
#endif
|
2009-06-18 17:44:48 +00:00
|
|
|
if (s_nounload || m_nounload) {
|
2006-06-16 15:46:29 +00:00
|
|
|
#ifdef _WINDOWS
|
2006-06-16 15:51:35 +00:00
|
|
|
typedef void (WINAPI *pFini)(HINSTANCE,DWORD,LPVOID);
|
2006-06-16 15:46:29 +00:00
|
|
|
pFini fini = (pFini)GetProcAddress(m_handle,"_DllMainCRTStartup");
|
|
|
|
if (!fini)
|
|
|
|
fini = (pFini)GetProcAddress(m_handle,"_CRT_INIT");
|
|
|
|
if (fini)
|
|
|
|
fini(m_handle,DLL_PROCESS_DETACH,NULL);
|
|
|
|
#else
|
|
|
|
typedef void (*pFini)();
|
|
|
|
pFini fini = (pFini)dlsym(m_handle,"_fini");
|
|
|
|
if (fini)
|
|
|
|
fini();
|
|
|
|
#endif
|
2009-06-18 17:44:48 +00:00
|
|
|
if (fini || m_nounload) {
|
2006-06-16 15:46:29 +00:00
|
|
|
checkPoint();
|
|
|
|
return;
|
|
|
|
}
|
2006-06-16 15:51:35 +00:00
|
|
|
Debug(DebugWarn,"Could not finalize, will dlclose(%p)",m_handle);
|
2006-06-16 15:46:29 +00:00
|
|
|
}
|
2005-06-02 09:29:09 +00:00
|
|
|
int err = dlclose(m_handle);
|
|
|
|
if (err)
|
|
|
|
Debug(DebugGoOn,"Error %d on dlclose(%p)",err,m_handle);
|
|
|
|
else if (s_keepclosing) {
|
|
|
|
int tries;
|
|
|
|
for (tries=0; tries<10; tries++)
|
|
|
|
if (dlclose(m_handle))
|
|
|
|
break;
|
|
|
|
if (tries)
|
|
|
|
Debug(DebugGoOn,"Made %d attempts to dlclose(%p)",tries,m_handle);
|
|
|
|
}
|
|
|
|
checkPoint();
|
|
|
|
}
|
|
|
|
|
2009-06-18 17:44:48 +00:00
|
|
|
SLib* SLib::load(const char* file, bool local, bool nounload)
|
2005-06-02 09:29:09 +00:00
|
|
|
{
|
|
|
|
DDebug(DebugAll,"SLib::load('%s')",file);
|
2006-05-27 14:53:18 +00:00
|
|
|
int flags = RTLD_NOW;
|
|
|
|
#ifdef RTLD_GLOBAL
|
|
|
|
if (!local)
|
|
|
|
flags |= RTLD_GLOBAL;
|
|
|
|
#endif
|
|
|
|
HMODULE handle = ::dlopen(file,flags);
|
2005-06-02 09:29:09 +00:00
|
|
|
if (handle)
|
2009-06-18 17:44:48 +00:00
|
|
|
return new SLib(handle,file,nounload);
|
2005-06-02 09:29:09 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
Debug(DebugWarn,"LoadLibrary error %u in '%s'",::GetLastError(),file);
|
|
|
|
#else
|
2009-06-04 14:01:17 +00:00
|
|
|
Debug(DebugWarn,"%s",dlerror());
|
2005-06-02 09:29:09 +00:00
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-24 21:09:41 +00:00
|
|
|
bool SLib::unload(bool unloadNow)
|
|
|
|
{
|
|
|
|
typedef bool (*pUnload)(bool);
|
2009-06-18 17:44:48 +00:00
|
|
|
if (m_nounload)
|
|
|
|
return false;
|
2008-01-24 21:09:41 +00:00
|
|
|
pUnload unl = (pUnload)dlsym(m_handle,"_unload");
|
|
|
|
return (unl != 0) && unl(unloadNow);
|
|
|
|
}
|
|
|
|
|
2007-11-26 23:56:37 +00:00
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
Engine::Engine()
|
|
|
|
{
|
2005-04-02 13:28:14 +00:00
|
|
|
DDebug(DebugAll,"Engine::Engine() [%p]",this);
|
2008-10-14 20:15:33 +00:00
|
|
|
initUsrPath(s_usrpath);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Engine::~Engine()
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
Debugger debug("Engine::~Engine()"," [%p]",this);
|
|
|
|
#endif
|
|
|
|
assert(this == s_self);
|
|
|
|
m_dispatcher.clear();
|
|
|
|
plugins.clear();
|
2004-05-24 00:38:23 +00:00
|
|
|
m_libs.clear();
|
2007-03-26 17:38:50 +00:00
|
|
|
s_mode = Stopped;
|
2004-05-22 00:05:20 +00:00
|
|
|
s_self = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Engine::run()
|
|
|
|
{
|
2005-04-09 22:10:00 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
// In Windows we must initialize the socket library very early because even trivial
|
|
|
|
// functions like endianess swapping - ntohl and family - need it to be initialized
|
|
|
|
WSADATA wsaData;
|
|
|
|
int errc = ::WSAStartup(MAKEWORD(2,2), &wsaData);
|
|
|
|
if (errc) {
|
2005-07-01 22:35:06 +00:00
|
|
|
Debug(DebugGoOn,"Failed to initialize the Windows Sockets library, error code %d",errc);
|
2005-04-09 22:10:00 +00:00
|
|
|
return errc & 127;
|
|
|
|
}
|
2005-11-07 03:09:23 +00:00
|
|
|
#else
|
|
|
|
::signal(SIGPIPE,SIG_IGN);
|
2005-04-09 22:10:00 +00:00
|
|
|
#endif
|
2005-04-28 22:46:59 +00:00
|
|
|
s_cfg = configFile(s_cfgfile);
|
|
|
|
s_cfg.load();
|
2007-05-16 12:10:44 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
int winTimerRes = s_cfg.getIntValue("general","wintimer");
|
|
|
|
if ((winTimerRes > 0) && (winTimerRes < 100)) {
|
|
|
|
typedef ULONG (__stdcall *NTSTR)(ULONG,BOOLEAN,PULONG);
|
|
|
|
String err;
|
|
|
|
HMODULE ntDll = GetModuleHandle("NTDLL.DLL");
|
|
|
|
if (ntDll) {
|
|
|
|
NTSTR ntSTR = (NTSTR)GetProcAddress(ntDll,"NtSetTimerResolution");
|
|
|
|
if (ntSTR) {
|
|
|
|
ULONG res = 0;
|
|
|
|
unsigned int ntstatus = ntSTR(10000*winTimerRes,true,&res);
|
|
|
|
if (ntstatus)
|
|
|
|
err << "NTSTATUS " << ntstatus;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
err = "NtSetTimerResolution not found";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
err = "NTDLL not found (Windows 9x or ME?)";
|
|
|
|
if (err)
|
|
|
|
Debug(DebugWarn,"Timer resolution not set: %s",err.c_str());
|
|
|
|
}
|
|
|
|
#endif
|
2010-03-31 09:36:58 +00:00
|
|
|
Thread::idleMsec(s_cfg.getIntValue("general","idlemsec",(clientMode() ? 2 * Thread::idleMsec() : 0)));
|
2007-05-16 12:10:44 +00:00
|
|
|
SysUsage::init();
|
2008-01-24 21:09:41 +00:00
|
|
|
|
2007-05-16 12:10:44 +00:00
|
|
|
s_runid = Time::secNow();
|
2008-01-19 11:19:52 +00:00
|
|
|
if (s_node.trimBlanks().null()) {
|
|
|
|
char hostName[HOST_NAME_MAX+1];
|
|
|
|
if (::gethostname(hostName,sizeof(hostName)))
|
|
|
|
hostName[0] = '\0';
|
|
|
|
s_node = s_cfg.getValue("general","nodename",hostName);
|
|
|
|
s_node.trimBlanks();
|
|
|
|
}
|
2008-01-24 21:09:41 +00:00
|
|
|
const char *modPath = s_cfg.getValue("general","modpath");
|
|
|
|
if (modPath)
|
|
|
|
s_modpath = modPath;
|
|
|
|
s_maxworkers = s_cfg.getIntValue("general","maxworkers",s_maxworkers);
|
|
|
|
s_restarts = s_cfg.getIntValue("general","restarts");
|
|
|
|
m_dispatcher.warnTime(1000*(u_int64_t)s_cfg.getIntValue("general","warntime"));
|
|
|
|
extraPath(clientMode() ? "client" : "server");
|
|
|
|
extraPath(s_cfg.getValue("general","extrapath"));
|
|
|
|
|
2008-01-24 11:43:04 +00:00
|
|
|
s_params.addParam("version",YATE_VERSION);
|
|
|
|
s_params.addParam("release",YATE_STATUS YATE_RELEASE);
|
|
|
|
s_params.addParam("nodename",s_node);
|
|
|
|
s_params.addParam("runid",String(s_runid));
|
|
|
|
s_params.addParam("configname",s_cfgfile);
|
|
|
|
s_params.addParam("sharedpath",s_shrpath);
|
|
|
|
s_params.addParam("configpath",s_cfgpath);
|
2008-10-14 20:15:33 +00:00
|
|
|
s_params.addParam("usercfgpath",s_usrpath);
|
2008-01-24 11:43:04 +00:00
|
|
|
s_params.addParam("cfgsuffix",s_cfgsuffix);
|
|
|
|
s_params.addParam("modulepath",s_modpath);
|
|
|
|
s_params.addParam("modsuffix",s_modsuffix);
|
|
|
|
s_params.addParam("logfile",s_logfile);
|
2010-01-27 12:07:51 +00:00
|
|
|
s_params.addParam("interactive",String::boolText(s_interactive));
|
2008-01-24 11:43:04 +00:00
|
|
|
s_params.addParam("clientmode",String::boolText(clientMode()));
|
|
|
|
s_params.addParam("supervised",String::boolText(s_super_handle >= 0));
|
2010-01-07 12:11:09 +00:00
|
|
|
s_params.addParam("runattempt",String(s_run_attempt));
|
2008-01-24 11:43:04 +00:00
|
|
|
s_params.addParam("maxworkers",String(s_maxworkers));
|
2007-08-09 10:48:58 +00:00
|
|
|
DDebug(DebugAll,"Engine::run()");
|
2004-05-22 00:05:20 +00:00
|
|
|
install(new EngineStatusHandler);
|
2008-01-24 21:09:41 +00:00
|
|
|
install(new EngineCommand);
|
|
|
|
install(new EngineHelp);
|
2004-05-22 00:05:20 +00:00
|
|
|
loadPlugins();
|
2005-07-01 22:35:06 +00:00
|
|
|
Debug(DebugAll,"Loaded %d plugins",plugins.count());
|
2004-11-01 00:07:00 +00:00
|
|
|
if (s_super_handle >= 0) {
|
|
|
|
install(new EngineSuperHandler);
|
|
|
|
if (s_restarts)
|
|
|
|
s_restarts = 1000000 * s_restarts + Time::now();
|
|
|
|
}
|
|
|
|
else if (s_restarts) {
|
|
|
|
Debug(DebugWarn,"No supervisor - disabling automatic restarts");
|
|
|
|
s_restarts = 0;
|
|
|
|
}
|
2004-05-22 00:05:20 +00:00
|
|
|
initPlugins();
|
2005-06-02 09:29:09 +00:00
|
|
|
checkPoint();
|
2004-05-22 00:05:20 +00:00
|
|
|
::signal(SIGINT,sighandler);
|
|
|
|
::signal(SIGTERM,sighandler);
|
2005-07-01 22:35:06 +00:00
|
|
|
Debug(DebugAll,"Engine dispatching start message");
|
2010-06-16 11:42:52 +00:00
|
|
|
dispatch("engine.start",true);
|
2005-05-20 23:08:16 +00:00
|
|
|
setStatus(SERVICE_RUNNING);
|
2005-05-31 19:04:18 +00:00
|
|
|
long corr = 0;
|
2005-04-02 00:49:38 +00:00
|
|
|
#ifndef _WINDOWS
|
2004-05-22 00:05:20 +00:00
|
|
|
::signal(SIGHUP,sighandler);
|
|
|
|
::signal(SIGQUIT,sighandler);
|
2005-09-29 19:34:23 +00:00
|
|
|
::signal(SIGCHLD,sighandler);
|
|
|
|
::signal(SIGUSR1,sighandler);
|
|
|
|
::signal(SIGUSR2,sighandler);
|
2005-04-02 00:49:38 +00:00
|
|
|
#endif
|
2008-01-19 11:19:52 +00:00
|
|
|
Output("Yate%s engine is initialized and starting up%s%s",
|
|
|
|
clientMode() ? " client" : "",s_node.null() ? "" : " on " ,s_node.safe());
|
2010-06-16 09:05:08 +00:00
|
|
|
int stops = MAX_STOP;
|
2010-06-16 11:42:52 +00:00
|
|
|
while (s_haltcode == -1 || ((--stops >= 0) && dispatch("engine.stop",true))) {
|
2005-01-24 15:02:14 +00:00
|
|
|
if (s_cmds) {
|
|
|
|
Output("Executing initial commands");
|
2005-04-08 12:45:19 +00:00
|
|
|
for (ObjList* c = s_cmds->skipNull(); c; c=c->skipNext()) {
|
2005-01-24 15:02:14 +00:00
|
|
|
String* s = static_cast<String*>(c->get());
|
2005-04-08 12:45:19 +00:00
|
|
|
Message m("engine.command");
|
|
|
|
m.addParam("line",*s);
|
|
|
|
if (dispatch(m)) {
|
|
|
|
if (m.retValue())
|
|
|
|
Output("%s",m.retValue().c_str());
|
2005-01-24 15:02:14 +00:00
|
|
|
}
|
2005-04-08 12:45:19 +00:00
|
|
|
else
|
|
|
|
Debug(DebugWarn,"Unrecognized command '%s'",s->c_str());
|
2005-01-24 15:02:14 +00:00
|
|
|
}
|
2007-05-15 15:40:50 +00:00
|
|
|
destruct(s_cmds);
|
2005-01-24 15:02:14 +00:00
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
if (s_init) {
|
|
|
|
s_init = false;
|
|
|
|
initPlugins();
|
|
|
|
}
|
|
|
|
|
2006-06-10 12:33:16 +00:00
|
|
|
if (s_debug) {
|
|
|
|
// one-time sending of debug setup messages
|
|
|
|
s_debug = false;
|
|
|
|
const NamedList* sect = s_cfg.getSection("debug");
|
|
|
|
if (sect) {
|
|
|
|
unsigned int n = sect->length();
|
|
|
|
for (unsigned int i = 0; i < n; i++) {
|
|
|
|
const NamedString* str = sect->getParam(i);
|
|
|
|
if (!(str && str->name() && *str))
|
|
|
|
continue;
|
|
|
|
Message* m = new Message("engine.debug");
|
|
|
|
m->addParam("module",str->name());
|
|
|
|
m->addParam("line",*str);
|
|
|
|
enqueue(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
// Create worker thread if we didn't hear about any of them in a while
|
|
|
|
if (s_makeworker && (EnginePrivate::count < s_maxworkers)) {
|
2005-08-02 02:20:00 +00:00
|
|
|
Debug(EnginePrivate::count ? DebugMild : DebugInfo,
|
|
|
|
"Creating new message dispatching thread (%d running)",EnginePrivate::count);
|
2004-11-01 00:07:00 +00:00
|
|
|
EnginePrivate *prv = new EnginePrivate;
|
|
|
|
prv->startup();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
2004-06-03 22:26:29 +00:00
|
|
|
else
|
|
|
|
s_makeworker = true;
|
2004-05-22 00:05:20 +00:00
|
|
|
|
2004-11-01 00:07:00 +00:00
|
|
|
if (s_restarts && (Time::now() >= s_restarts)) {
|
|
|
|
if (!(usedPlugins() || dispatch("engine.busy"))) {
|
|
|
|
s_haltcode = 128;
|
|
|
|
break;
|
|
|
|
}
|
2005-09-29 19:34:23 +00:00
|
|
|
DDebug(DebugAll,"Engine busy - will try to restart later");
|
2004-11-01 00:07:00 +00:00
|
|
|
// If we cannot restart now try again in 10s
|
|
|
|
s_restarts = Time::now() + 10000000;
|
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
// Attempt to sleep until the next full second
|
2005-05-31 19:04:18 +00:00
|
|
|
long t = 1000000 - (long)(Time::now() % 1000000) - corr;
|
|
|
|
if (t < 250000)
|
|
|
|
t += 1000000;
|
|
|
|
XDebug(DebugAll,"Sleeping for %ld",t);
|
|
|
|
Thread::usleep(t);
|
2010-06-16 11:42:52 +00:00
|
|
|
Message* m = new Message("engine.timer",0,true);
|
2004-06-03 22:26:29 +00:00
|
|
|
m->addParam("time",String((int)m->msgTime().sec()));
|
2010-06-16 08:46:47 +00:00
|
|
|
if (nodeName())
|
|
|
|
m->addParam("nodename",nodeName());
|
2010-06-16 09:05:08 +00:00
|
|
|
if (s_haltcode == -1) {
|
|
|
|
// Try to fine tune the ticker unless exiting
|
|
|
|
t = (long)(m->msgTime().usec() % 1000000);
|
|
|
|
if (t > 500000)
|
|
|
|
corr -= (1000000-t)/10;
|
|
|
|
else
|
|
|
|
corr += t/10;
|
|
|
|
XDebug(DebugAll,"Adjustment at %ld, corr %ld",t,corr);
|
|
|
|
}
|
2004-06-03 22:26:29 +00:00
|
|
|
enqueue(m);
|
2004-10-21 13:50:45 +00:00
|
|
|
Thread::yield();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
2004-12-01 14:25:30 +00:00
|
|
|
s_haltcode &= 0xff;
|
2005-01-09 06:42:56 +00:00
|
|
|
Output("Yate engine is shutting down with code %d",s_haltcode);
|
2005-05-20 23:08:16 +00:00
|
|
|
setStatus(SERVICE_STOP_PENDING);
|
2007-07-31 15:14:09 +00:00
|
|
|
::signal(SIGINT,SIG_DFL);
|
2010-06-16 11:42:52 +00:00
|
|
|
dispatch("engine.halt",true);
|
2005-06-02 09:29:09 +00:00
|
|
|
checkPoint();
|
2005-04-23 19:33:37 +00:00
|
|
|
Thread::msleep(200);
|
2004-05-22 00:05:20 +00:00
|
|
|
m_dispatcher.dequeue();
|
2005-06-02 09:29:09 +00:00
|
|
|
checkPoint();
|
2006-01-18 16:06:05 +00:00
|
|
|
// We are occasionally doing things that can cause crashes so don't abort
|
2006-07-17 13:33:02 +00:00
|
|
|
abortOnBug(s_sigabrt && s_lateabrt);
|
2004-05-22 00:05:20 +00:00
|
|
|
Thread::killall();
|
2005-06-02 09:29:09 +00:00
|
|
|
checkPoint();
|
2004-05-22 00:05:20 +00:00
|
|
|
m_dispatcher.dequeue();
|
|
|
|
::signal(SIGTERM,SIG_DFL);
|
2005-04-02 00:49:38 +00:00
|
|
|
#ifndef _WINDOWS
|
2004-05-22 00:05:20 +00:00
|
|
|
::signal(SIGHUP,SIG_DFL);
|
|
|
|
::signal(SIGQUIT,SIG_DFL);
|
2005-04-02 00:49:38 +00:00
|
|
|
#endif
|
2004-05-22 00:05:20 +00:00
|
|
|
delete this;
|
2005-07-01 22:35:06 +00:00
|
|
|
Debug(DebugAll,"Exiting with %d locked mutexes",Mutex::locks());
|
2005-04-09 22:10:00 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
::WSACleanup();
|
|
|
|
#endif
|
2005-05-20 23:08:16 +00:00
|
|
|
setStatus(SERVICE_STOPPED);
|
2004-05-22 00:05:20 +00:00
|
|
|
return s_haltcode;
|
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
Engine* Engine::self()
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
if (!s_self)
|
|
|
|
s_self = new Engine;
|
|
|
|
return s_self;
|
|
|
|
}
|
|
|
|
|
2005-07-04 12:53:04 +00:00
|
|
|
const char* Engine::pathSeparator()
|
|
|
|
{
|
|
|
|
return PATH_SEP;
|
|
|
|
}
|
|
|
|
|
2008-10-14 20:15:33 +00:00
|
|
|
const String& Engine::configPath(bool user)
|
2005-04-02 00:49:38 +00:00
|
|
|
{
|
2006-06-11 16:50:04 +00:00
|
|
|
if (user) {
|
2008-10-14 20:15:33 +00:00
|
|
|
if (s_createusr) {
|
|
|
|
// create user data dir on first request
|
|
|
|
s_createusr = false;
|
|
|
|
if (::mkdir(s_usrpath,S_IRWXU) == 0)
|
|
|
|
Debug(DebugNote,"Created user data directory: '%s'",s_usrpath.c_str());
|
|
|
|
}
|
|
|
|
return s_usrpath;
|
2006-06-11 16:50:04 +00:00
|
|
|
}
|
2008-10-14 20:15:33 +00:00
|
|
|
return s_cfgpath;
|
|
|
|
}
|
|
|
|
|
|
|
|
String Engine::configFile(const char* name, bool user)
|
|
|
|
{
|
|
|
|
String path = configPath(user);
|
2006-06-11 16:50:04 +00:00
|
|
|
if (!path.endsWith(PATH_SEP))
|
|
|
|
path += PATH_SEP;
|
|
|
|
return path + name + s_cfgsuffix;
|
2005-04-02 00:49:38 +00:00
|
|
|
}
|
|
|
|
|
2005-04-28 22:46:59 +00:00
|
|
|
const Configuration& Engine::config()
|
|
|
|
{
|
|
|
|
return s_cfg;
|
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
bool Engine::Register(const Plugin* plugin, bool reg)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2004-11-29 21:01:04 +00:00
|
|
|
DDebug(DebugInfo,"Engine::Register(%p,%d)",plugin,reg);
|
2004-05-22 00:05:20 +00:00
|
|
|
ObjList *p = plugins.find(plugin);
|
|
|
|
if (reg) {
|
|
|
|
if (p)
|
|
|
|
return false;
|
2007-11-26 23:56:37 +00:00
|
|
|
if (plugin->earlyInit()) {
|
|
|
|
s_loadMode = LoadEarly;
|
|
|
|
p = plugins.insert(plugin);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
p = plugins.append(plugin);
|
2004-05-22 00:05:20 +00:00
|
|
|
p->setDelete(s_dynplugin);
|
|
|
|
}
|
|
|
|
else if (p)
|
|
|
|
p->remove(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-06-18 17:44:48 +00:00
|
|
|
bool Engine::loadPlugin(const char* file, bool local, bool nounload)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
s_dynplugin = false;
|
2007-11-26 23:56:37 +00:00
|
|
|
s_loadMode = Engine::LoadLate;
|
2009-06-18 17:44:48 +00:00
|
|
|
SLib *lib = SLib::load(file,local,nounload);
|
2004-05-22 00:05:20 +00:00
|
|
|
s_dynplugin = true;
|
|
|
|
if (lib) {
|
2007-11-26 23:56:37 +00:00
|
|
|
switch (s_loadMode) {
|
|
|
|
case LoadFail:
|
|
|
|
delete lib;
|
|
|
|
return false;
|
|
|
|
case LoadEarly:
|
|
|
|
// load early - unload late
|
|
|
|
m_libs.append(lib);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
m_libs.insert(lib);
|
|
|
|
break;
|
|
|
|
}
|
2004-05-22 00:05:20 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-11-26 23:56:37 +00:00
|
|
|
void Engine::pluginMode(PluginMode mode)
|
|
|
|
{
|
|
|
|
s_loadMode = mode;
|
|
|
|
}
|
|
|
|
|
2005-07-01 21:12:16 +00:00
|
|
|
bool Engine::loadPluginDir(const String& relPath)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
2005-08-19 20:23:51 +00:00
|
|
|
Debugger debug("Engine::loadPluginDir","('%s')",relPath.c_str());
|
2004-05-22 00:05:20 +00:00
|
|
|
#endif
|
2005-04-28 22:46:59 +00:00
|
|
|
bool defload = s_cfg.getBoolValue("general","modload",true);
|
2005-07-01 21:12:16 +00:00
|
|
|
String path = s_modpath;
|
|
|
|
if (relPath) {
|
|
|
|
if (!path.endsWith(PATH_SEP))
|
|
|
|
path += PATH_SEP;
|
|
|
|
path += relPath;
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
2005-07-01 21:12:16 +00:00
|
|
|
if (path.endsWith(PATH_SEP))
|
|
|
|
path = path.substr(0,path.length()-1);
|
2005-04-02 00:49:38 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
WIN32_FIND_DATA entry;
|
2005-07-01 21:12:16 +00:00
|
|
|
HANDLE hf = ::FindFirstFile(path + PATH_SEP "*",&entry);
|
2005-04-02 00:49:38 +00:00
|
|
|
if (hf == INVALID_HANDLE_VALUE) {
|
2005-07-01 21:12:16 +00:00
|
|
|
Debug(DebugWarn,"Engine::loadPlugins() failed directory '%s'",path.safe());
|
|
|
|
return false;
|
2005-04-02 00:49:38 +00:00
|
|
|
}
|
|
|
|
do {
|
|
|
|
XDebug(DebugInfo,"Found dir entry %s",entry.cFileName);
|
|
|
|
int n = ::strlen(entry.cFileName) - s_modsuffix.length();
|
|
|
|
if ((n > 0) && !::strcmp(entry.cFileName+n,s_modsuffix)) {
|
2005-04-28 22:46:59 +00:00
|
|
|
if (s_cfg.getBoolValue("modules",entry.cFileName,defload))
|
2009-06-18 17:44:48 +00:00
|
|
|
loadPlugin(path + PATH_SEP + entry.cFileName,false,
|
|
|
|
s_cfg.getBoolValue("nounload",entry.cFileName));
|
2005-04-02 00:49:38 +00:00
|
|
|
}
|
2009-12-28 13:20:07 +00:00
|
|
|
} while (::FindNextFile(hf,&entry) && !exiting());
|
2005-04-02 00:49:38 +00:00
|
|
|
::FindClose(hf);
|
|
|
|
#else
|
2005-07-01 21:12:16 +00:00
|
|
|
DIR *dir = ::opendir(path);
|
2004-05-22 00:05:20 +00:00
|
|
|
if (!dir) {
|
2005-07-01 21:12:16 +00:00
|
|
|
Debug(DebugWarn,"Engine::loadPlugins() failed directory '%s'",path.safe());
|
|
|
|
return false;
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
struct dirent *entry;
|
2009-12-28 13:20:07 +00:00
|
|
|
while (((entry = ::readdir(dir)) != 0) && !exiting()) {
|
2005-04-02 00:49:38 +00:00
|
|
|
XDebug(DebugInfo,"Found dir entry %s",entry->d_name);
|
2004-05-22 00:05:20 +00:00
|
|
|
int n = ::strlen(entry->d_name) - s_modsuffix.length();
|
|
|
|
if ((n > 0) && !::strcmp(entry->d_name+n,s_modsuffix)) {
|
2005-04-28 22:46:59 +00:00
|
|
|
if (s_cfg.getBoolValue("modules",entry->d_name,defload))
|
2006-05-27 14:53:18 +00:00
|
|
|
loadPlugin(path + PATH_SEP + entry->d_name,
|
2009-06-18 17:44:48 +00:00
|
|
|
s_cfg.getBoolValue("localsym",entry->d_name,s_localsymbol),
|
|
|
|
s_cfg.getBoolValue("nounload",entry->d_name));
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
::closedir(dir);
|
2005-04-02 00:49:38 +00:00
|
|
|
#endif
|
2005-07-01 21:12:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::loadPlugins()
|
|
|
|
{
|
|
|
|
NamedList *l = s_cfg.getSection("preload");
|
|
|
|
if (l) {
|
|
|
|
unsigned int len = l->length();
|
|
|
|
for (unsigned int i=0; i<len; i++) {
|
|
|
|
NamedString *n = l->getParam(i);
|
|
|
|
if (n && n->toBoolean())
|
|
|
|
loadPlugin(n->name());
|
2009-12-28 13:20:07 +00:00
|
|
|
if (exiting())
|
|
|
|
break;
|
2005-07-01 21:12:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
loadPluginDir(String::empty());
|
2007-07-23 16:18:18 +00:00
|
|
|
while (GenObject* extra = s_extramod.remove(false)) {
|
|
|
|
loadPluginDir(extra->toString());
|
|
|
|
extra->destruct();
|
|
|
|
}
|
2005-04-28 22:46:59 +00:00
|
|
|
l = s_cfg.getSection("postload");
|
2004-05-22 00:05:20 +00:00
|
|
|
if (l) {
|
|
|
|
unsigned int len = l->length();
|
|
|
|
for (unsigned int i=0; i<len; i++) {
|
2009-12-28 13:20:07 +00:00
|
|
|
if (exiting())
|
|
|
|
return;
|
2004-05-22 00:05:20 +00:00
|
|
|
NamedString *n = l->getParam(i);
|
|
|
|
if (n && n->toBoolean())
|
|
|
|
loadPlugin(n->name());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::initPlugins()
|
|
|
|
{
|
2009-12-28 13:20:07 +00:00
|
|
|
if (exiting())
|
|
|
|
return;
|
2005-06-20 20:51:17 +00:00
|
|
|
Output("Initializing plugins");
|
2010-06-16 11:42:52 +00:00
|
|
|
dispatch("engine.init",true);
|
2005-04-08 12:45:19 +00:00
|
|
|
ObjList *l = plugins.skipNull();
|
|
|
|
for (; l; l = l->skipNext()) {
|
2004-05-22 00:05:20 +00:00
|
|
|
Plugin *p = static_cast<Plugin *>(l->get());
|
2005-04-08 12:45:19 +00:00
|
|
|
p->initialize();
|
2009-12-28 13:20:07 +00:00
|
|
|
if (exiting()) {
|
|
|
|
Output("Initialization aborted, exiting...");
|
|
|
|
return;
|
|
|
|
}
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
2005-06-20 20:51:17 +00:00
|
|
|
Output("Initialization complete");
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2004-11-01 00:07:00 +00:00
|
|
|
int Engine::usedPlugins()
|
|
|
|
{
|
|
|
|
int used = 0;
|
2005-04-08 12:45:19 +00:00
|
|
|
ObjList *l = plugins.skipNull();
|
|
|
|
for (; l; l = l->skipNext()) {
|
2004-11-01 00:07:00 +00:00
|
|
|
Plugin *p = static_cast<Plugin *>(l->get());
|
2005-04-08 12:45:19 +00:00
|
|
|
if (p->isBusy())
|
2004-11-01 00:07:00 +00:00
|
|
|
used++;
|
|
|
|
}
|
|
|
|
return used;
|
|
|
|
}
|
|
|
|
|
2007-07-23 16:18:18 +00:00
|
|
|
void Engine::extraPath(const String& path)
|
|
|
|
{
|
|
|
|
if (path.null() || s_extramod.find(path))
|
|
|
|
return;
|
|
|
|
s_extramod.append(new String(path));
|
|
|
|
}
|
|
|
|
|
2008-10-14 20:15:33 +00:00
|
|
|
void Engine::userPath(const String& path)
|
|
|
|
{
|
|
|
|
if (path.null())
|
|
|
|
return;
|
|
|
|
if (s_usrpath.null())
|
|
|
|
s_userdir = path;
|
|
|
|
else
|
|
|
|
Debug(DebugWarn,"Engine::userPath('%s') called too late!",path.c_str());
|
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
void Engine::halt(unsigned int code)
|
|
|
|
{
|
2005-06-24 23:32:58 +00:00
|
|
|
if (s_haltcode == -1)
|
|
|
|
s_haltcode = code;
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2005-09-29 19:34:23 +00:00
|
|
|
bool Engine::restart(unsigned int code, bool gracefull)
|
2005-07-29 23:32:19 +00:00
|
|
|
{
|
|
|
|
if ((s_super_handle < 0) || (s_haltcode != -1))
|
|
|
|
return false;
|
2005-09-29 19:34:23 +00:00
|
|
|
if (gracefull)
|
|
|
|
s_restarts = 1;
|
|
|
|
else
|
|
|
|
s_haltcode = (code & 0xff) | 0x80;
|
2005-07-29 23:32:19 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
void Engine::init()
|
|
|
|
{
|
|
|
|
s_init = true;
|
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
bool Engine::install(MessageHandler* handler)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
return s_self ? s_self->m_dispatcher.install(handler) : false;
|
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
bool Engine::uninstall(MessageHandler* handler)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
return s_self ? s_self->m_dispatcher.uninstall(handler) : false;
|
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
bool Engine::enqueue(Message* msg)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
return (msg && s_self) ? s_self->m_dispatcher.enqueue(msg) : false;
|
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
bool Engine::dispatch(Message* msg)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
return (msg && s_self) ? s_self->m_dispatcher.dispatch(*msg) : false;
|
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
bool Engine::dispatch(Message& msg)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
return s_self ? s_self->m_dispatcher.dispatch(msg) : false;
|
|
|
|
}
|
|
|
|
|
2010-06-16 11:42:52 +00:00
|
|
|
bool Engine::dispatch(const char* name, bool broadcast)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
if (!(s_self && name && *name))
|
|
|
|
return false;
|
2010-06-16 11:42:52 +00:00
|
|
|
Message msg(name,0,broadcast);
|
2010-06-16 08:46:47 +00:00
|
|
|
if (nodeName())
|
|
|
|
msg.addParam("nodename",nodeName());
|
2004-05-22 00:05:20 +00:00
|
|
|
return s_self->m_dispatcher.dispatch(msg);
|
|
|
|
}
|
|
|
|
|
2005-11-26 18:26:46 +00:00
|
|
|
unsigned int Engine::runId()
|
|
|
|
{
|
|
|
|
return s_runid;
|
|
|
|
}
|
|
|
|
|
2005-05-05 17:02:18 +00:00
|
|
|
static void usage(bool client, FILE* f)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
::fprintf(f,
|
2005-01-24 15:02:14 +00:00
|
|
|
"Usage: yate [options] [commands ...]\n"
|
2005-06-13 12:08:56 +00:00
|
|
|
" -h, --help Display help message (this one) and exit\n"
|
|
|
|
" -V, --version Display program version and exit\n"
|
2004-05-22 00:05:20 +00:00
|
|
|
" -v Verbose debugging (you can use more than once)\n"
|
|
|
|
" -q Quieter debugging (you can use more than once)\n"
|
2005-05-05 17:02:18 +00:00
|
|
|
"%s"
|
2004-09-05 23:55:26 +00:00
|
|
|
" -p filename Write PID to file\n"
|
2005-04-02 00:49:38 +00:00
|
|
|
" -l filename Log to file\n"
|
2005-01-10 17:57:37 +00:00
|
|
|
" -n configname Use specified configuration name (%s)\n"
|
2007-11-15 23:06:36 +00:00
|
|
|
" -e pathname Path to shared files directory (" SHR_PATH ")\n"
|
2004-05-22 00:05:20 +00:00
|
|
|
" -c pathname Path to conf files directory (" CFG_PATH ")\n"
|
2008-10-14 20:15:33 +00:00
|
|
|
" -u pathname Path to user files directory (%s)\n"
|
2004-05-22 00:05:20 +00:00
|
|
|
" -m pathname Path to modules directory (" MOD_PATH ")\n"
|
2007-07-23 16:18:18 +00:00
|
|
|
" -x relpath Relative path to extra modules directory (can be repeated)\n"
|
2005-05-24 15:09:19 +00:00
|
|
|
" -w directory Change working directory\n"
|
2008-01-19 11:19:52 +00:00
|
|
|
" -N nodename Set the name of this node in a cluster\n"
|
2006-06-20 20:17:32 +00:00
|
|
|
#ifdef RLIMIT_CORE
|
|
|
|
" -C Enable core dumps if possible\n"
|
|
|
|
#endif
|
2008-03-10 15:40:54 +00:00
|
|
|
#ifdef RLIMIT_NOFILE
|
|
|
|
" -F Increase the maximum file handle to compiled value\n"
|
|
|
|
#endif
|
2009-02-26 16:26:55 +00:00
|
|
|
" -t Truncate log file, don't append to it\n"
|
2004-05-22 00:05:20 +00:00
|
|
|
" -D[options] Special debugging options\n"
|
2004-10-14 16:36:24 +00:00
|
|
|
" a Abort if bugs are encountered\n"
|
2005-08-02 02:20:00 +00:00
|
|
|
" m Attempt to debug mutex deadlocks\n"
|
2006-05-27 14:53:18 +00:00
|
|
|
#ifdef RTLD_GLOBAL
|
|
|
|
" l Try to keep module symbols local\n"
|
|
|
|
#endif
|
2004-05-22 00:05:20 +00:00
|
|
|
" c Call dlclose() until it gets an error\n"
|
2006-06-16 15:46:29 +00:00
|
|
|
" u Do not unload modules on exit, just finalize\n"
|
2004-05-22 00:05:20 +00:00
|
|
|
" i Reinitialize after 1st initialization\n"
|
|
|
|
" x Exit immediately after initialization\n"
|
|
|
|
" w Delay creation of 1st worker thread\n"
|
2006-05-19 15:52:05 +00:00
|
|
|
" o Colorize output using ANSI codes\n"
|
2006-07-17 13:33:02 +00:00
|
|
|
" s Abort on bugs even during shutdown\n"
|
2006-12-16 01:07:26 +00:00
|
|
|
" t Timestamp debugging messages relative to program start\n"
|
2006-12-22 00:57:35 +00:00
|
|
|
" e Timestamp debugging messages based on EPOCH (1-1-1970 GMT)\n"
|
|
|
|
" f Timestamp debugging in GMT format YYYYMMDDhhmmss.uuuuuu\n"
|
2005-05-05 17:02:18 +00:00
|
|
|
,client ? "" :
|
2005-05-20 23:08:16 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
" --service Run as Windows service\n"
|
|
|
|
" --install Install the Windows service\n"
|
|
|
|
" --remove Remove the Windows service\n"
|
|
|
|
#else
|
2005-05-05 17:02:18 +00:00
|
|
|
" -d Daemonify, suppress output unless logged\n"
|
|
|
|
" -s Supervised, restart if crashes or locks up\n"
|
2007-01-25 20:46:32 +00:00
|
|
|
" -r Enable rotation of log file (needs -s and -l)\n"
|
2005-05-20 23:08:16 +00:00
|
|
|
#endif
|
2008-10-14 20:15:33 +00:00
|
|
|
,s_cfgfile.safe()
|
2008-10-14 21:32:45 +00:00
|
|
|
,s_usrpath.safe());
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2005-05-05 17:02:18 +00:00
|
|
|
static void badopt(bool client, char chr, const char* opt)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
if (chr)
|
|
|
|
::fprintf(stderr,"Invalid character '%c' in option '%s'\n",chr,opt);
|
|
|
|
else
|
|
|
|
::fprintf(stderr,"Invalid option '%s'\n",opt);
|
2005-05-05 17:02:18 +00:00
|
|
|
usage(client,stderr);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2005-05-05 17:02:18 +00:00
|
|
|
static void noarg(bool client, const char* opt)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
::fprintf(stderr,"Missing parameter to option '%s'\n",opt);
|
2005-05-05 17:02:18 +00:00
|
|
|
usage(client,stderr);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2005-06-13 12:08:56 +00:00
|
|
|
static void version()
|
|
|
|
{
|
2008-02-04 12:54:30 +00:00
|
|
|
::fprintf(stdout,"Yate " YATE_VERSION " " YATE_STATUS YATE_RELEASE "\n");
|
2005-06-13 12:08:56 +00:00
|
|
|
}
|
|
|
|
|
2005-05-20 23:08:16 +00:00
|
|
|
int Engine::main(int argc, const char** argv, const char** env, RunMode mode, bool fail)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2005-05-20 23:08:16 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
int service = 0;
|
|
|
|
#else
|
2004-05-22 00:05:20 +00:00
|
|
|
bool daemonic = false;
|
2004-10-21 13:50:45 +00:00
|
|
|
bool supervised = false;
|
2005-04-02 00:49:38 +00:00
|
|
|
#endif
|
2009-07-14 18:47:06 +00:00
|
|
|
bool client = (mode == Client);
|
2006-12-22 00:57:35 +00:00
|
|
|
Debugger::Formatting tstamp = Debugger::None;
|
2006-05-19 15:52:05 +00:00
|
|
|
bool colorize = false;
|
2005-05-24 15:09:19 +00:00
|
|
|
const char* pidfile = 0;
|
|
|
|
const char* workdir = 0;
|
2008-10-14 20:15:33 +00:00
|
|
|
const char* usrpath = 0;
|
2005-04-02 00:49:38 +00:00
|
|
|
int debug_level = debugLevel();
|
2009-06-18 12:21:23 +00:00
|
|
|
|
2009-07-22 12:57:14 +00:00
|
|
|
Lockable::startUsingNow();
|
2005-01-10 17:57:37 +00:00
|
|
|
|
2006-06-12 12:16:29 +00:00
|
|
|
const char* cfgfile = ::strrchr(argv[0],'/');
|
|
|
|
if (!cfgfile)
|
|
|
|
cfgfile = ::strrchr(argv[0],'\\');
|
|
|
|
if (cfgfile)
|
|
|
|
cfgfile++;
|
2005-04-09 22:10:00 +00:00
|
|
|
|
2006-06-12 12:16:29 +00:00
|
|
|
if (!cfgfile)
|
|
|
|
cfgfile = argv[0][0] ? argv[0] : "yate";
|
2005-01-10 17:57:37 +00:00
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
int i;
|
|
|
|
bool inopt = true;
|
|
|
|
for (i=1;i<argc;i++) {
|
|
|
|
const char *pc = argv[i];
|
|
|
|
if (inopt && (pc[0] == '-') && pc[1]) {
|
|
|
|
while (pc && *++pc) {
|
|
|
|
switch (*pc) {
|
|
|
|
case '-':
|
|
|
|
if (!*++pc) {
|
|
|
|
inopt=false;
|
|
|
|
pc=0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!::strcmp(pc,"help")) {
|
2008-10-19 16:28:54 +00:00
|
|
|
s_mode = mode;
|
2008-10-14 20:15:33 +00:00
|
|
|
initUsrPath(s_usrpath);
|
2005-05-05 17:02:18 +00:00
|
|
|
usage(client,stdout);
|
2004-05-22 00:05:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2005-06-13 12:08:56 +00:00
|
|
|
else if (!::strcmp(pc,"version")) {
|
|
|
|
version();
|
|
|
|
return 0;
|
|
|
|
}
|
2005-05-20 23:08:16 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
else if (!(client ||::strcmp(pc,"service"))) {
|
|
|
|
service |= YSERV_RUN;
|
|
|
|
pc = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (!(client || ::strcmp(pc,"install"))) {
|
|
|
|
service |= YSERV_INS;
|
|
|
|
pc = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (!(client || ::strcmp(pc,"remove"))) {
|
|
|
|
service |= YSERV_DEL;
|
|
|
|
pc = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
2008-10-14 20:15:33 +00:00
|
|
|
initUsrPath(s_usrpath);
|
2005-05-05 17:02:18 +00:00
|
|
|
badopt(client,0,argv[i]);
|
2004-05-22 00:05:20 +00:00
|
|
|
return EINVAL;
|
|
|
|
break;
|
|
|
|
case 'h':
|
2008-10-19 16:28:54 +00:00
|
|
|
s_mode = mode;
|
2008-10-14 20:15:33 +00:00
|
|
|
initUsrPath(s_usrpath);
|
2005-05-05 17:02:18 +00:00
|
|
|
usage(client,stdout);
|
2004-05-22 00:05:20 +00:00
|
|
|
return 0;
|
|
|
|
case 'v':
|
|
|
|
debug_level++;
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
debug_level--;
|
|
|
|
break;
|
2005-04-02 00:49:38 +00:00
|
|
|
#ifndef _WINDOWS
|
2004-05-22 00:05:20 +00:00
|
|
|
case 'd':
|
|
|
|
daemonic = true;
|
|
|
|
break;
|
2004-10-21 13:50:45 +00:00
|
|
|
case 's':
|
|
|
|
supervised = true;
|
|
|
|
break;
|
2007-01-25 20:46:32 +00:00
|
|
|
case 'r':
|
|
|
|
s_logrotator = true;
|
|
|
|
break;
|
2005-04-02 00:49:38 +00:00
|
|
|
#endif
|
2009-02-26 16:26:55 +00:00
|
|
|
case 't':
|
|
|
|
s_logtruncate = true;
|
|
|
|
break;
|
2005-04-02 00:49:38 +00:00
|
|
|
case 'p':
|
2004-05-22 00:05:20 +00:00
|
|
|
if (i+1 >= argc) {
|
2005-05-05 17:02:18 +00:00
|
|
|
noarg(client,argv[i]);
|
2004-05-22 00:05:20 +00:00
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
pc = 0;
|
2005-04-02 00:49:38 +00:00
|
|
|
pidfile=argv[++i];
|
2004-05-22 00:05:20 +00:00
|
|
|
break;
|
2005-04-02 00:49:38 +00:00
|
|
|
case 'l':
|
2004-09-05 23:55:26 +00:00
|
|
|
if (i+1 >= argc) {
|
2005-05-05 17:02:18 +00:00
|
|
|
noarg(client,argv[i]);
|
2004-09-05 23:55:26 +00:00
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
pc = 0;
|
2005-05-24 15:09:19 +00:00
|
|
|
s_logfile=argv[++i];
|
2004-09-05 23:55:26 +00:00
|
|
|
break;
|
2005-01-09 06:05:02 +00:00
|
|
|
case 'n':
|
|
|
|
if (i+1 >= argc) {
|
2005-05-05 17:02:18 +00:00
|
|
|
noarg(client,argv[i]);
|
2005-01-09 06:05:02 +00:00
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
pc = 0;
|
2006-06-12 12:16:29 +00:00
|
|
|
cfgfile=argv[++i];
|
2005-01-09 06:05:02 +00:00
|
|
|
break;
|
2007-11-15 23:06:36 +00:00
|
|
|
case 'e':
|
|
|
|
if (i+1 >= argc) {
|
|
|
|
noarg(client,argv[i]);
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
pc = 0;
|
|
|
|
s_shrpath=argv[++i];
|
|
|
|
break;
|
2004-05-22 00:05:20 +00:00
|
|
|
case 'c':
|
|
|
|
if (i+1 >= argc) {
|
2005-05-05 17:02:18 +00:00
|
|
|
noarg(client,argv[i]);
|
2004-05-22 00:05:20 +00:00
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
pc = 0;
|
|
|
|
s_cfgpath=argv[++i];
|
|
|
|
break;
|
2008-10-14 20:15:33 +00:00
|
|
|
case 'u':
|
|
|
|
if (i+1 >= argc) {
|
|
|
|
noarg(client,argv[i]);
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
pc = 0;
|
|
|
|
usrpath=argv[++i];
|
|
|
|
break;
|
2004-05-22 00:05:20 +00:00
|
|
|
case 'm':
|
|
|
|
if (i+1 >= argc) {
|
2005-05-05 17:02:18 +00:00
|
|
|
noarg(client,argv[i]);
|
2004-05-22 00:05:20 +00:00
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
pc = 0;
|
|
|
|
s_modpath=argv[++i];
|
|
|
|
break;
|
2005-05-24 15:09:19 +00:00
|
|
|
case 'w':
|
|
|
|
if (i+1 >= argc) {
|
|
|
|
noarg(client,argv[i]);
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
pc = 0;
|
|
|
|
workdir = argv[++i];
|
|
|
|
break;
|
2007-07-23 16:18:18 +00:00
|
|
|
case 'x':
|
|
|
|
if (i+1 >= argc) {
|
|
|
|
noarg(client,argv[i]);
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
pc = 0;
|
|
|
|
extraPath(argv[++i]);
|
|
|
|
break;
|
2008-01-19 11:19:52 +00:00
|
|
|
case 'N':
|
|
|
|
if (i+1 >= argc) {
|
|
|
|
noarg(client,argv[i]);
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
pc = 0;
|
|
|
|
s_node=argv[++i];
|
|
|
|
break;
|
2006-06-20 20:17:32 +00:00
|
|
|
#ifdef RLIMIT_CORE
|
|
|
|
case 'C':
|
|
|
|
s_coredump = true;
|
|
|
|
break;
|
2008-03-10 15:40:54 +00:00
|
|
|
#endif
|
|
|
|
#ifdef RLIMIT_NOFILE
|
|
|
|
case 'F':
|
|
|
|
s_numfiles = true;
|
|
|
|
break;
|
2006-06-20 20:17:32 +00:00
|
|
|
#endif
|
2004-05-22 00:05:20 +00:00
|
|
|
case 'D':
|
|
|
|
while (*++pc) {
|
|
|
|
switch (*pc) {
|
2004-10-14 16:36:24 +00:00
|
|
|
case 'a':
|
2004-10-24 00:51:51 +00:00
|
|
|
s_sigabrt = true;
|
2004-10-14 16:36:24 +00:00
|
|
|
break;
|
2006-07-17 13:33:02 +00:00
|
|
|
case 's':
|
|
|
|
s_lateabrt = true;
|
|
|
|
break;
|
2005-08-02 02:20:00 +00:00
|
|
|
case 'm':
|
2009-12-10 11:20:50 +00:00
|
|
|
{
|
|
|
|
unsigned long lockWait = Lockable::wait();
|
|
|
|
if (lockWait) {
|
|
|
|
lockWait /= 2;
|
|
|
|
if (lockWait < Thread::idleUsec())
|
|
|
|
lockWait = Thread::idleUsec();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
lockWait = 10000000;
|
|
|
|
Lockable::wait(lockWait);
|
|
|
|
}
|
2005-08-02 02:20:00 +00:00
|
|
|
break;
|
2006-05-27 14:53:18 +00:00
|
|
|
#ifdef RTLD_GLOBAL
|
|
|
|
case 'l':
|
|
|
|
s_localsymbol = true;
|
|
|
|
break;
|
|
|
|
#endif
|
2004-05-22 00:05:20 +00:00
|
|
|
case 'c':
|
|
|
|
s_keepclosing = true;
|
|
|
|
break;
|
2006-06-16 15:46:29 +00:00
|
|
|
case 'u':
|
|
|
|
s_nounload = true;
|
|
|
|
break;
|
2004-05-22 00:05:20 +00:00
|
|
|
case 'i':
|
|
|
|
s_init = true;
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
s_haltcode++;
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
s_makeworker = false;
|
|
|
|
break;
|
2006-05-19 15:52:05 +00:00
|
|
|
case 'o':
|
|
|
|
colorize = true;
|
|
|
|
break;
|
2006-12-16 01:07:26 +00:00
|
|
|
case 'e':
|
2006-12-22 00:57:35 +00:00
|
|
|
tstamp = Debugger::Absolute;
|
|
|
|
break;
|
2005-04-22 20:07:26 +00:00
|
|
|
case 't':
|
2006-12-22 00:57:35 +00:00
|
|
|
tstamp = Debugger::Relative;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
tstamp = Debugger::Textual;
|
2005-04-22 20:07:26 +00:00
|
|
|
break;
|
2004-05-22 00:05:20 +00:00
|
|
|
default:
|
2008-10-14 20:15:33 +00:00
|
|
|
initUsrPath(s_usrpath);
|
2005-05-05 17:02:18 +00:00
|
|
|
badopt(client,*pc,argv[i]);
|
2004-05-22 00:05:20 +00:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pc = 0;
|
|
|
|
break;
|
2005-06-13 12:08:56 +00:00
|
|
|
case 'V':
|
|
|
|
version();
|
|
|
|
return 0;
|
2004-05-22 00:05:20 +00:00
|
|
|
default:
|
2008-10-14 20:15:33 +00:00
|
|
|
initUsrPath(s_usrpath);
|
2005-05-05 17:02:18 +00:00
|
|
|
badopt(client,*pc,argv[i]);
|
2004-05-22 00:05:20 +00:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2005-01-24 15:02:14 +00:00
|
|
|
if (!s_cmds)
|
|
|
|
s_cmds = new ObjList;
|
|
|
|
s_cmds->append(new String(argv[i]));
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
}
|
2005-01-10 17:57:37 +00:00
|
|
|
|
2005-05-05 17:02:18 +00:00
|
|
|
if (fail)
|
|
|
|
return EINVAL;
|
|
|
|
|
2007-03-26 17:38:50 +00:00
|
|
|
s_mode = mode;
|
|
|
|
|
2006-06-12 12:16:29 +00:00
|
|
|
s_cfgfile = cfgfile;
|
|
|
|
if (s_cfgfile.endsWith(".exe") || s_cfgfile.endsWith(".EXE"))
|
|
|
|
s_cfgfile = s_cfgfile.substr(0,s_cfgfile.length()-4);
|
|
|
|
|
2008-10-14 20:15:33 +00:00
|
|
|
initUsrPath(s_usrpath,usrpath);
|
|
|
|
|
2009-06-01 20:05:02 +00:00
|
|
|
if (workdir && ::chdir(workdir)) {
|
|
|
|
int err = errno;
|
|
|
|
::fprintf(stderr,"Could not change working directory to '%s': %s (%d)\n",
|
|
|
|
workdir,::strerror(err),err);
|
|
|
|
return err;
|
|
|
|
}
|
2005-05-24 15:09:19 +00:00
|
|
|
|
2009-04-02 14:35:51 +00:00
|
|
|
if (s_engineCheck && !s_engineCheck->check(s_cmds))
|
|
|
|
return s_haltcode;
|
|
|
|
|
2005-05-20 23:08:16 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
if ((mode == Server) && !service)
|
|
|
|
service = YSERV_RUN;
|
|
|
|
|
|
|
|
if (service & YSERV_DEL) {
|
|
|
|
if (service & (YSERV_RUN|YSERV_INS)) {
|
|
|
|
::fprintf(stderr,"Option --remove prohibits --install and --service\n");
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
SC_HANDLE sc = OpenSCManager(0,0,SC_MANAGER_ALL_ACCESS);
|
|
|
|
if (!sc) {
|
2005-06-02 09:29:09 +00:00
|
|
|
::fprintf(stderr,"Could not open Service Manager, code %u\n",::GetLastError());
|
2005-05-20 23:08:16 +00:00
|
|
|
return EPERM;
|
|
|
|
}
|
|
|
|
SC_HANDLE sv = OpenService(sc,"yate",DELETE|SERVICE_STOP);
|
|
|
|
if (sv) {
|
|
|
|
ControlService(sv,SERVICE_CONTROL_STOP,0);
|
|
|
|
if (!DeleteService(sv)) {
|
2005-06-02 09:29:09 +00:00
|
|
|
DWORD err = ::GetLastError();
|
2005-05-20 23:08:16 +00:00
|
|
|
if (err != ERROR_SERVICE_MARKED_FOR_DELETE)
|
|
|
|
::fprintf(stderr,"Could not delete Service, code %u\n",err);
|
|
|
|
}
|
|
|
|
CloseServiceHandle(sv);
|
|
|
|
}
|
|
|
|
else {
|
2005-06-02 09:29:09 +00:00
|
|
|
DWORD err = ::GetLastError();
|
2005-05-20 23:08:16 +00:00
|
|
|
if (err != ERROR_SERVICE_DOES_NOT_EXIST)
|
|
|
|
::fprintf(stderr,"Could not open Service, code %u\n",err);
|
|
|
|
}
|
|
|
|
CloseServiceHandle(sc);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (service & YSERV_INS) {
|
|
|
|
char buf[1024];
|
|
|
|
if (!GetModuleFileName(0,buf,sizeof(buf))) {
|
2005-06-02 09:29:09 +00:00
|
|
|
::fprintf(stderr,"Could not find my own executable file, code %u\n",::GetLastError());
|
2005-05-20 23:08:16 +00:00
|
|
|
return EINVAL;
|
|
|
|
}
|
2005-05-24 15:09:19 +00:00
|
|
|
String s(buf);
|
2005-05-20 23:08:16 +00:00
|
|
|
if (mode != Server)
|
2005-05-24 15:09:19 +00:00
|
|
|
s << " --service";
|
|
|
|
if (workdir)
|
|
|
|
s << " -w \"" << workdir << "\"";
|
|
|
|
|
2005-05-20 23:08:16 +00:00
|
|
|
SC_HANDLE sc = OpenSCManager(0,0,SC_MANAGER_ALL_ACCESS);
|
|
|
|
if (!sc) {
|
2005-06-02 09:29:09 +00:00
|
|
|
::fprintf(stderr,"Could not open Service Manager, code %u\n",::GetLastError());
|
2005-05-20 23:08:16 +00:00
|
|
|
return EPERM;
|
|
|
|
}
|
|
|
|
SC_HANDLE sv = CreateService(sc,"yate","Yet Another Telephony Engine",GENERIC_EXECUTE,
|
|
|
|
SERVICE_WIN32_OWN_PROCESS,SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,
|
2005-05-24 15:09:19 +00:00
|
|
|
s.c_str(),0,0,0,0,0);
|
2005-05-20 23:08:16 +00:00
|
|
|
if (sv)
|
|
|
|
CloseServiceHandle(sv);
|
|
|
|
else
|
2005-06-02 09:29:09 +00:00
|
|
|
::fprintf(stderr,"Could not create Service, code %u\n",::GetLastError());
|
2005-05-20 23:08:16 +00:00
|
|
|
CloseServiceHandle(sc);
|
|
|
|
if (!(service & YSERV_RUN))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else
|
2005-05-05 17:02:18 +00:00
|
|
|
if (client && (daemonic || supervised)) {
|
|
|
|
::fprintf(stderr,"Options -d and -s not supported in client mode\n");
|
|
|
|
return EINVAL;
|
|
|
|
}
|
2006-05-19 16:04:59 +00:00
|
|
|
if (colorize && s_logfile) {
|
|
|
|
::fprintf(stderr,"Option -Do not supported when logging to file\n");
|
|
|
|
return EINVAL;
|
|
|
|
}
|
2007-01-25 20:46:32 +00:00
|
|
|
if (s_logrotator && !(supervised && s_logfile)) {
|
|
|
|
::fprintf(stderr,"Option -r needs supervisor and logging to file\n");
|
|
|
|
return EINVAL;
|
|
|
|
}
|
2006-05-19 15:52:05 +00:00
|
|
|
Debugger::enableOutput(true,colorize);
|
2004-05-22 00:05:20 +00:00
|
|
|
if (daemonic) {
|
|
|
|
Debugger::enableOutput(false);
|
2005-01-19 08:52:02 +00:00
|
|
|
// Make sure X client modules fail initialization in daemon mode
|
|
|
|
::unsetenv("DISPLAY");
|
2004-05-22 00:05:20 +00:00
|
|
|
if (::daemon(1,0) == -1) {
|
|
|
|
int err = errno;
|
|
|
|
::fprintf(stderr,"Daemonification failed: %s (%d)\n",::strerror(err),err);
|
|
|
|
return err;
|
|
|
|
}
|
2010-01-27 12:07:51 +00:00
|
|
|
s_interactive = false;
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
2005-04-02 00:49:38 +00:00
|
|
|
#endif
|
2005-01-10 17:57:37 +00:00
|
|
|
|
2004-09-05 23:55:26 +00:00
|
|
|
if (pidfile) {
|
|
|
|
int fd = ::open(pidfile,O_WRONLY|O_CREAT,0644);
|
|
|
|
if (fd >= 0) {
|
|
|
|
char pid[32];
|
|
|
|
::snprintf(pid,sizeof(pid),"%u\n",::getpid());
|
|
|
|
::write(fd,pid,::strlen(pid));
|
|
|
|
::close(fd);
|
|
|
|
}
|
|
|
|
}
|
2005-01-10 17:57:37 +00:00
|
|
|
|
2005-05-24 15:09:19 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
if (!service)
|
|
|
|
#endif
|
|
|
|
logFileOpen();
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
debugLevel(debug_level);
|
2004-11-01 00:07:00 +00:00
|
|
|
abortOnBug(s_sigabrt);
|
2004-10-21 13:50:45 +00:00
|
|
|
|
2006-06-20 20:17:32 +00:00
|
|
|
#ifdef RLIMIT_CORE
|
|
|
|
while (s_coredump) {
|
2009-06-22 11:09:38 +00:00
|
|
|
#ifdef HAVE_PRCTL
|
|
|
|
#ifdef PR_SET_DUMPABLE
|
|
|
|
prctl(PR_SET_DUMPABLE,1,0,0,0);
|
|
|
|
#endif
|
|
|
|
#endif
|
2006-06-20 20:17:32 +00:00
|
|
|
struct rlimit lim;
|
|
|
|
if (!::getrlimit(RLIMIT_CORE,&lim)) {
|
|
|
|
errno = 0;
|
|
|
|
lim.rlim_cur = lim.rlim_max;
|
|
|
|
// if limit is zero but user is root set limit to infinity
|
|
|
|
if (!(lim.rlim_cur || ::getuid()))
|
|
|
|
lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
|
|
|
|
if (lim.rlim_cur && !::setrlimit(RLIMIT_CORE,&lim))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Debug(DebugWarn,"Could not enable core dumps: %s (%d)",
|
|
|
|
errno ? strerror(errno) : "hard limit",errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2008-03-10 15:40:54 +00:00
|
|
|
#ifdef RLIMIT_NOFILE
|
|
|
|
while (s_numfiles) {
|
|
|
|
struct rlimit lim;
|
|
|
|
if (!::getrlimit(RLIMIT_NOFILE,&lim)) {
|
|
|
|
errno = 0;
|
|
|
|
if (lim.rlim_cur >= FDSIZE_HACK)
|
|
|
|
break;
|
|
|
|
lim.rlim_cur = FDSIZE_HACK;
|
|
|
|
if (lim.rlim_max < FDSIZE_HACK)
|
|
|
|
lim.rlim_max = FDSIZE_HACK;
|
|
|
|
if (!::setrlimit(RLIMIT_NOFILE,&lim))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Debug(DebugWarn,"Could not increase max file handle: %s (%d)",
|
|
|
|
errno ? strerror(errno) : "hard limit",errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2006-06-20 20:17:32 +00:00
|
|
|
|
2005-04-02 00:49:38 +00:00
|
|
|
int retcode = -1;
|
|
|
|
#ifndef _WINDOWS
|
|
|
|
if (supervised)
|
2005-04-02 13:28:14 +00:00
|
|
|
retcode = supervise();
|
2004-10-21 13:50:45 +00:00
|
|
|
if (retcode >= 0)
|
|
|
|
return retcode;
|
2005-04-02 00:49:38 +00:00
|
|
|
#endif
|
2004-10-21 13:50:45 +00:00
|
|
|
|
2006-12-22 00:57:35 +00:00
|
|
|
Debugger::setFormatting(tstamp);
|
2005-05-20 23:08:16 +00:00
|
|
|
|
|
|
|
#ifdef _WINDOWS
|
2010-01-27 12:07:51 +00:00
|
|
|
if (service) {
|
|
|
|
s_interactive = false;
|
2005-06-02 09:29:09 +00:00
|
|
|
retcode = ::StartServiceCtrlDispatcher(dispatchTable) ? 0 : ::GetLastError();
|
2010-01-27 12:07:51 +00:00
|
|
|
}
|
2005-05-20 23:08:16 +00:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
retcode = engineRun();
|
|
|
|
|
2004-10-21 13:50:45 +00:00
|
|
|
return retcode;
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
2005-03-28 00:58:26 +00:00
|
|
|
|
2005-05-05 17:02:18 +00:00
|
|
|
void Engine::help(bool client, bool errout)
|
|
|
|
{
|
2008-10-14 20:15:33 +00:00
|
|
|
initUsrPath(s_usrpath);
|
2005-05-05 17:02:18 +00:00
|
|
|
usage(client, errout ? stderr : stdout);
|
|
|
|
}
|
|
|
|
|
2005-03-28 00:58:26 +00:00
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|