Patch level : 10.0

Files correlati     : lurch.exe
Ricompilazione Demo : [ ]
Commento            :
Questo maggiordomo non solo e' in grado di ammazzare la servitu' oziosa...
ma anche di risuscitarla quanto questa si suicida!


git-svn-id: svn://10.65.10.50/trunk@19979 c028cbd2-c16b-5b4b-a496-9718f37d4682
This commit is contained in:
guy 2010-01-25 15:36:05 +00:00
parent 28fb3889c5
commit 46d30d0ca2
4 changed files with 253 additions and 197 deletions

View File

@ -15,7 +15,7 @@
// --------------------------------------------------------------------------
// headers
// --------------------------------------------------------------------------
#include <wx/wxprec.h>
#include "baseserv.h"
#include <wx/config.h>
@ -25,12 +25,10 @@
#include <wx/mstream.h>
#include <wx/sckstrm.h>
#ifdef WIN32
#ifndef __WXMSW__
#include <wx/fileconf.h>
#endif
#include <wx/app.h>
///////////////////////////////////////////////////////////
// Utilities
///////////////////////////////////////////////////////////
@ -589,6 +587,11 @@ const wxString& TBaseServerApp::GetConfigName() const
void TBaseServerApp::SetConfigString(const wxChar* key, const wxChar* val, const wxChar* app) const
{
#ifdef __WXMSW__
if (app == NULL || *app == '\0')
app = GetAppName();
::WritePrivateProfileString(app, key, val, GetConfigName());
#else
wxFileConfig ini("", "", GetConfigName(), "", wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_RELATIVE_PATH);
wxString str;
if (app == NULL || *app == '\0')
@ -596,6 +599,7 @@ void TBaseServerApp::SetConfigString(const wxChar* key, const wxChar* val, const
str << '/' << app;
ini.SetPath(str);
ini.Write(key, val);
#endif
}
void TBaseServerApp::SetConfigInt(const wxChar* key, int val, const wxChar* app) const
@ -606,13 +610,19 @@ void TBaseServerApp::SetConfigInt(const wxChar* key, int val, const wxChar* app)
wxString TBaseServerApp::GetConfigString(const wxChar* key, const wxChar* def, const wxChar* app) const
{
wxFileConfig ini("", "", GetConfigName(), "", wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_RELATIVE_PATH);
wxString str;
if (app == NULL || *app == '\0')
if (app == NULL || *app == '\0')
app = GetAppName();
#ifdef __WXMSW__
wxChar value[512]; memset(value, 0, sizeof(value));
const int len = ::GetPrivateProfileString(app, key, def, value, sizeof(value)-1, GetConfigName());
str = len <= 0 ? def : value;
#else
wxFileConfig ini("", "", GetConfigName(), "", wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_RELATIVE_PATH);
str << '/' << app;
ini.SetPath(str);
ini.Read(key, &str, def);
#endif
return str;
}

View File

@ -1,11 +1,12 @@
#include <wx/wxprec.h>
#ifndef __BASESERV_H__
#define __BASESERV_H__
#include <wx/app.h>
#include <wx/datetime.h>
#include <wx/hash.h>
#include <wx/snglinst.h>
#include <wx/socket.h>
#include <wx/wfstream.h>
#ifdef LINUX
#include <wx/app.h>
#endif
#include "xml.h"
@ -150,3 +151,5 @@ public:
};
TBaseServerApp& GetServerApp();
#endif

View File

@ -3,56 +3,36 @@
#include <wx/config.h>
#include <wx/filename.h>
#include <wx/process.h>
#ifdef WIN32
#include <wx/fileconf.h>
#endif
#include <ctype.h>
///////////////////////////////////////////////////////////
// TProcess declaration
///////////////////////////////////////////////////////////
class TLurchServer; //segnaposto della TLurchServer che serve alla TProcess
class TProcess : public wxProcess
{
TLurchServer* m_pLurch;
wxString m_strApp;
protected:
virtual void OnTerminate(int pid, int status);
public:
void ForcePid(int pid) { SetPid(pid); }
TProcess(TLurchServer* pLurch, const wxString& strApp) : m_pLurch(pLurch), m_strApp(strApp) {}
};
#include <wx/timer.h>
///////////////////////////////////////////////////////////
// TLurchServer declaration
///////////////////////////////////////////////////////////
//classe TProcessHashMap derivata da wxHashMap (è una specie di assocarray!)
//classe TProcessHashMap derivata da wxHashMap (è l'equivalente di TAssoc_array)
WX_DECLARE_HASH_MAP( wxString, wxProcess*, wxStringHash, wxStringEqual, TProcessHashMap );
class TLurchServer : public TBaseServerApp
{
TProcessHashMap m_ProcMap;
wxTimer m_Timer;
int m_nFreq;
TProcessHashMap m_hmProcMap;
wxSemaphore m_Semaphore;
wxTimer m_PingTimer;
wxArrayString m_aServers;
DECLARE_EVENT_TABLE();
protected:
virtual const wxChar* GetAppName() const;
virtual bool Initialization();
void OnTimer(wxTimerEvent& evt);
bool RestartTimer();
void OnEndProcess(wxProcessEvent& evt);
void AddMiniForm(TXmlItem& tr, const wxChar* action, const wxChar* app, const wxChar* prompt) const;
TXmlItem& AddMiniForm(TXmlItem& tr, const wxChar* action, const wxChar* app, const wxChar* prompt) const;
void EnumerateVariables(const wxString& strApp, wxArrayString& arr) const;
void CreateServersList(wxArrayString& arr) const;
const wxArrayString& GetServersList();
const TProcessHashMap& GetRunningServers() { return m_hmProcMap; }
bool PingProcess(const wxString& strApp);
void StopProcess(const wxString& strApp);
wxString StartProcess(const wxString& strApp);
@ -70,116 +50,150 @@ public:
//metodi riguardanti l'interfaccia html
void ProcessFormStart(const THashTable& args, wxSocketBase& sock);
void ProcessFormStop(const THashTable& args, wxSocketBase& sock);
void ProcessFormRestart(const THashTable& args, wxSocketBase& sock);
void ProcessFormConfig(const THashTable& args, wxSocketBase& sock);
void ProcessFormUpdate(THashTable& args, wxSocketBase& sock);
void CallCgi(wxString& strFileName, wxSocketBase& sock);
TLurchServer();
};
///////////////////////////////////////////////////////////
// TProcess implementation
///////////////////////////////////////////////////////////
void TProcess::OnTerminate(int pid, int WXUNUSED(status))
{
SetPid(pid);
m_pLurch->ForgetProcess(m_strApp);
}
///////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
// TLurchServer implementation
///////////////////////////////////////////////////////////
BEGIN_EVENT_TABLE(TLurchServer, TBaseServerApp)
EVT_TIMER(wxID_ANY, TLurchServer::OnTimer)
EVT_TIMER(wxID_ANY, TLurchServer::OnTimer)
EVT_END_PROCESS(wxID_ANY, TLurchServer::OnEndProcess)
END_EVENT_TABLE()
#ifndef max
#define max(a,b) ((a)>(b) ? (a) : (b))
#endif
bool TLurchServer::PingProcess(const wxString& strApp)
{
bool bPinged = false;
TProcess* pProcess = (TProcess*)m_ProcMap[strApp];
if (pProcess != NULL)
const wxString strPort = GetConfigString("Port", "", strApp);
if (!strPort.IsEmpty())
{
const wxString strPort = GetConfigString("Port", "", strApp);
if (!strPort.IsEmpty())
const int nInterval = m_PingTimer.GetInterval(); // msec
const int nTimeOut = max(nInterval/4, 250); // msec
wxIPV4address ipAddress;
ipAddress.LocalHost();
ipAddress.Service(strPort);
wxSocketClient sSock(wxSOCKET_NOWAIT);
sSock.Connect(ipAddress, false);
if (sSock.WaitOnConnect(0, nTimeOut))
{
const int nTimeOut = m_nFreq > 3000 ? m_nFreq / 3000 : 1;
wxIPV4address ipAddress;
ipAddress.LocalHost();
ipAddress.Service(strPort);
wxSocketClient sSock(wxSOCKET_NOWAIT);
sSock.Connect(ipAddress, false);
if (sSock.WaitOnConnect(nTimeOut))
sSock.Discard(); // Tralascia eventuali dati in arrivo non richiesti
const wxString strPing = wxT("PING\n");
sSock.Write(strPing, strPing.Len());
if (sSock.WaitForWrite(0, nTimeOut))
{
sSock.Write("PING\n", 5);
if (sSock.WaitForWrite(nTimeOut))
{
char buffer[8]; memset(buffer, 0, sizeof(buffer));
sSock.Read(buffer, 4);
if (sSock.WaitForRead(nTimeOut))
bPinged = wxStrcmp(buffer, "PONG") == 0;
}
::wxMilliSleep(nTimeOut); // Triste necessita' :-( Aspetto qui ...
char buffer[8]; memset(buffer, 0, sizeof(buffer));
sSock.Read(buffer, 4);
if (sSock.WaitForRead(0, 1)) // ... ma poi non aspetto qua :-)
bPinged = wxStrncmp(buffer, "PONG", 4) == 0;
sSock.Discard(); // Tralascia ulteriori dati in arrivo
}
}
}
return bPinged;
}
void TLurchServer::OnTimer(wxTimerEvent& WXUNUSED(evt))
void TLurchServer::OnTimer(wxTimerEvent& evt)
{
m_Timer.Stop();
const wxString strApp = "Authorization";
if (!PingProcess(strApp))
if (m_Semaphore.TryWait() != wxSEMA_NO_ERROR)
{
TProcess* pProcess = (TProcess*)m_ProcMap[strApp];
wxKillError ke = pProcess->Kill(pProcess->GetPid());
if (ke == wxKILL_OK)
WriteLog(strApp + " killed!");
else
{
wxString strMsg;
strMsg << "Error " << ke << " killing " << strApp;
WriteLog(strMsg);
}
wxSleep(2);
StartProcess(strApp);
evt.Skip();
return;
}
const TProcessHashMap& hmServers = GetRunningServers();
const int nServers = hmServers.size();
if (nServers > 0) // Is anybody out there?
{
const int nRandomIndex = rand() % nServers;
wxString strApp; // Usually "Authorization"
TProcessHashMap::const_iterator it;
for (it = hmServers.begin(); it != hmServers.end(); ++it)
strApp = it->first;
if (!PingProcess(strApp))
{
wxProcess* pProcess = m_hmProcMap[strApp];
wxKillError ke = pProcess->Kill(pProcess->GetPid());
if (ke == wxKILL_OK)
WriteLog(strApp + _(" killed!"));
else
{
wxString strMsg;
strMsg << _("Error ") << ke << _(" killing ") << strApp;
WriteLog(strMsg);
}
wxSleep(2);
StartProcess(strApp);
}
}
m_Semaphore.Post();
}
void TLurchServer::OnEndProcess(wxProcessEvent& evt)
{
TProcessHashMap::const_iterator it;
for (it = m_hmProcMap.begin(); it != m_hmProcMap.end(); ++it)
{
const wxProcess* p = it->second;
if (p->GetPid() == evt.GetPid())
{
ForgetProcess(it->first);
break;
}
}
RestartTimer();
}
const wxChar* TLurchServer::GetAppName() const
{ return wxT("Lurch"); }
const wxArrayString& TLurchServer::GetServersList()
{
return "Lurch";
if (m_aServers.IsEmpty())
{
wxFileInputStream ini(GetConfigName());
const size_t size = ini.GetSize();
wxChar* buff = new wxChar[size];
ini.Read(buff, size);
const char* aperta = strchr(buff, '[');
while (aperta != NULL)
{
char* chiusa = (char*)strchr(aperta+1, ']');
if (chiusa != NULL)
{
*chiusa = '\0';
wxString str = aperta+1;
m_aServers.Add(str);
aperta = strchr(chiusa+1, '[');
}
else
break;
}
}
return m_aServers;
}
void TLurchServer::CreateServersList(wxArrayString& arr) const
TXmlItem& TLurchServer::AddMiniForm(TXmlItem& tr, const wxChar* action, const wxChar* app, const wxChar* prompt) const
{
wxFileInputStream ini(GetConfigName());
const size_t size = ini.GetSize();
wxChar* buff = new wxChar[size];
ini.Read(buff, size);
const char* aperta = strchr(buff, '[');
while (aperta != NULL)
{
char* chiusa = (char*)strchr(aperta+1, ']');
if (chiusa != NULL)
{
*chiusa = '\0';
wxString str = aperta+1;
arr.Add(str);
aperta = strchr(chiusa+1, '[');
}
else
break;
}
delete buff;
}
void TLurchServer::AddMiniForm(TXmlItem& tr, const wxChar* action, const wxChar* app, const wxChar* prompt) const
{
TXmlItem& td = tr.AddChild("td").SetAttr("width", "15%");
TXmlItem& form = td.AddChild("center").AddChild("form");
TXmlItem& td = tr.AddChild("td").SetAttr("width", "10%");
td.SetAttr("align", "center");
td.SetAttr("valign", "center"); // Lo ignora ma insisto
TXmlItem& form = td.AddChild("form");
form.SetAttr("action", action);
TXmlItem& name = form.AddChild("input");
@ -189,6 +203,7 @@ void TLurchServer::AddMiniForm(TXmlItem& tr, const wxChar* action, const wxChar*
TXmlItem& submit = form.AddChild("input");
submit.SetAttr("type", "submit");
submit.SetAttr("value", prompt);
return submit;
}
void TLurchServer::GenerateFile(wxString& strFilename)
@ -203,30 +218,21 @@ void TLurchServer::GenerateFile(wxString& strFilename)
strFilename = GetTempFilename();
const wxString strLurchName = GetAppName();
wxArrayString arr; CreateServersList(arr);
const wxArrayString& arr = GetServersList();
for (size_t i = 0; i < arr.GetCount(); i++)
{
const bool bLurch = arr[i] == strLurchName;
wxFileConfig ini("", "", GetConfigName(), "", wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_RELATIVE_PATH);
wxString str;
str << '/' << arr[i];
ini.SetPath(str);
const wxString& strApp = arr[i];
const bool bLurch = strApp == strLurchName;
const wxString strHost = GetConfigString("Host", "127.0.0.1", strApp);
const int nPort = GetConfigInt("Port", 3883, strApp);
const wxString strIcon = GetConfigString("Icon", "euro.gif", strApp);
wxString strHost;
ini.Read("Host", &strHost, "127.0.0.1");
int nPort;
ini.Read("Port", &nPort, 3883);
wxString strIcon;
ini.Read("Icon", &strIcon, "euro.gif");
const wxSingleInstanceChecker sic(arr[i]);
const wxSingleInstanceChecker sic(strApp);
const bool bRunning = sic.IsAnotherRunning();
TXmlItem& tr = table.AddChild("tr");
TXmlItem& td0 = tr.AddChild("td");
td0.SetAttr("width", "15%"); td0.SetAttr("align", "center");
td0.SetAttr("width", "10%"); td0.SetAttr("align", "center");
TXmlItem& a = td0.AddChild("a");
if (!bLurch && bRunning)
{
@ -236,8 +242,17 @@ void TLurchServer::GenerateFile(wxString& strFilename)
TXmlItem& img = a.AddChild("img");
img.SetAttr("src", strIcon); img.SetAttr("border", 0L); img.SetAttr("alt", arr[i]);
AddMiniForm(tr, (bRunning || bLurch) ? "kill.cgi" : "start.cgi", arr[i], (bRunning || bLurch) ? "Stop" : "Start");
AddMiniForm(tr, "config.cgi", arr[i], "Configure");
TXmlItem& buttStart = AddMiniForm(tr, "start.cgi", arr[i], _("Start"));
if (bRunning || bLurch)
buttStart.SetAttr(wxT("type"), wxT("hidden"));
TXmlItem& buttStop = AddMiniForm(tr, "kill.cgi", arr[i], _("Stop"));
if (!(bRunning || bLurch))
buttStop.SetAttr(wxT("type"), wxT("hidden"));
TXmlItem& buttRestart = AddMiniForm(tr, "restart.cgi", arr[i], _("Restart"));
if (!(bRunning && !bLurch))
buttRestart.SetAttr(wxT("type"), wxT("hidden"));
TXmlItem& a3 = tr.AddChild("td").AddChild("a");
if (!bLurch && bRunning)
@ -264,7 +279,7 @@ void TLurchServer::GenerateFile(wxString& strFilename)
TXmlItem& tr2 = panel.AddChild("tr");
tr2.AddChild("td").AddEnclosedText("Ping Frequency");
wxString strFreq; strFreq << m_nFreq/1000;
wxString strFreq; strFreq << m_PingTimer.GetInterval()/1000;
tr2.AddChild("td").AddEnclosedText(strFreq);
html.Save(strFilename);
@ -301,22 +316,6 @@ bool TLurchServer::IsCgiName(wxString strFilename) const
return strExt == "cgi" || strExt == "exe";
}
bool TLurchServer::RestartTimer()
{
bool ok = true;
if (m_nFreq > 0)
{
ok = m_Timer.Start(m_nFreq) && m_Timer.IsRunning();
if (!ok)
{
wxString strMsg;
strMsg << "Error starting timer with " << m_nFreq << " ms frequency";
WriteLog(strMsg);
}
}
return ok;
}
wxString TLurchServer::StartProcess(const wxString& strApp)
{
bool ok = false;
@ -337,28 +336,26 @@ wxString TLurchServer::StartProcess(const wxString& strApp)
fnPath.SetPath(GetServerPath());
fnPath.SetFullName(strRun);
TProcess* pProcess = new TProcess(this, strApp);
const long nProc = wxExecute(fnPath.GetFullPath(), wxEXEC_ASYNC, pProcess);
if (nProc == 0 || nProc == -1)
wxProcess* pProcess = wxProcess::Open(fnPath.GetFullPath());
if (pProcess == NULL)
{
strMessage.Printf("Can't run %s executable (%s)", strApp.c_str(), strRun.c_str());
delete pProcess;
strMessage.Printf(_("Can't run %s executable (%s)"), strApp.c_str(), strRun.c_str());
}
else
{
pProcess->ForcePid(nProc);
m_ProcMap[strApp] = pProcess; //memorizza il numero del processo che ha lanciato per poterlo usare in fase di controllo
m_hmProcMap[strApp] = pProcess; // memorizza il numero del processo che ha lanciato per poterlo usare in fase di controllo
strMessage = wxEmptyString;
::wxSleep(1); // Lascia il tempo di inizializzarsi prima di compinciare a pingarlo!
}
}
else
strMessage.Printf("Can't find %s executable (%s)", strApp.c_str(), strRun.c_str());
strMessage.Printf(_("Can't find %s executable (%s)"), strApp.c_str(), strRun.c_str());
}
else
strMessage.Printf("%s il already running", strApp.c_str());
strMessage.Printf(_("%s il already running"), strApp.c_str());
if (strMessage.IsEmpty())
WriteLog(strApp + " started.");
WriteLog(strApp + _(" started."));
else
WriteLog(strMessage);
@ -372,16 +369,16 @@ void TLurchServer::ProcessFormStart(const THashTable& args, wxSocketBase& sock)
{
const wxString strMessage = StartProcess(strApp);
if (strMessage.IsEmpty())
MessageBox("Server Started", strApp, sock);
MessageBox(_("Server Started"), strApp, sock);
else
MessageBox("ERROR", strMessage, sock);
MessageBox(_("ERROR"), strMessage, sock);
}
}
bool TLurchServer::ForgetProcess(const wxString& strApp)
{
WriteLog(strApp + " terminated.");
return m_ProcMap.erase(strApp) != 0;
WriteLog(strApp + _(" terminated."));
return m_hmProcMap.erase(strApp) != 0;
}
void TLurchServer::StopProcess(const wxString& strApp)
@ -397,14 +394,25 @@ void TLurchServer::StopProcess(const wxString& strApp)
wxSocketClient sock;
if (sock.Connect(addr))
{
// Prima provo con le buone inviando una richiesta di stop
const wxString str = "GET /stop.cgi HTTP/1.1\r\n\r\n";
sock.Write(str, str.Length());
if (strHost == "localhost")
if (addr.IsLocalHost())
{
const wxSingleInstanceChecker sic(strApp);
for (int i = 0; i < 5 && sic.IsAnotherRunning(); i++)
int i;
for (i = 5; i >= 0 && sic.IsAnotherRunning(); i--)
wxSleep(1);
ForgetProcess(strApp);
// Se le buone non hanno funzionato ... passo alle cattive
if (i < 0)
{
wxProcess* p = m_hmProcMap[strApp];
if (p != NULL)
{
p->Kill(p->GetPid());
ForgetProcess(strApp);
}
}
}
}
}
@ -412,24 +420,46 @@ void TLurchServer::StopProcess(const wxString& strApp)
void TLurchServer::ProcessFormStop(const THashTable& args, wxSocketBase& sock)
{
const wxString strApp = args.Get("App");
if (strApp == GetAppName()) // Stop myself!
{
wxArrayString app; CreateServersList(app);
for (size_t i = 0; i < app.GetCount(); i++)
{
if (app[i] != GetAppName()) // Stop Children only!
{
const wxSingleInstanceChecker sic(app[i]);
if (sic.IsAnotherRunning())
StopProcess(app[i]);
}
}
}
StopProcess(strApp);
MessageBox("Server stopped", strApp, sock);
if (m_Semaphore.Wait() == wxSEMA_NO_ERROR)
{
const wxString strApp = args.Get("App");
if (strApp == GetAppName() || strApp.IsEmpty()) // Stop myself!
{
m_PingTimer.Stop(); // Stop ping process!
// Fill a safe array of names before killing the processes stored in the hash map
const TProcessHashMap& hmServers = GetRunningServers(); // Hash map of the running processes
wxArrayString aRunner; // Array of the names of the runners
TProcessHashMap::const_iterator it;
for (it = hmServers.begin(); it != hmServers.end(); ++it)
aRunner.Add(it->first);
for (size_t i = 0; i < aRunner.GetCount(); i++)
StopProcess(aRunner[i]);
ExitMainLoop();
}
else
StopProcess(strApp);
MessageBox("Server stopped", strApp, sock);
m_Semaphore.Post();
}
}
void TLurchServer::ProcessFormRestart(const THashTable& args, wxSocketBase& sock)
{
const wxString strApp = args.Get("App");
if (!strApp.IsEmpty() && strApp != GetAppName())
{
if (m_Semaphore.Wait() == wxSEMA_NO_ERROR)
{
StopProcess(strApp);
::wxSleep(2);
ProcessFormStart(args, sock);
m_Semaphore.Post();
}
}
}
void TLurchServer::EnumerateVariables(const wxString& strApp, wxArrayString& arr) const
{
wxFileInputStream inf(GetConfigName());
@ -542,10 +572,13 @@ void TLurchServer::CallCgi(wxString& strFileName, wxSocketBase& sock)
if (strExt == "cgi")
{
strName.MakeLower();
if (strName == "start")
ProcessFormStart(hashArgs, sock); else
if (strName == "kill")
ProcessFormStop(hashArgs, sock); else
if (strName == "restart")
ProcessFormRestart(hashArgs, sock); else
if (strName == "config")
ProcessFormConfig(hashArgs, sock); else
if (strName == "update")
@ -593,23 +626,32 @@ void TLurchServer::ProcessHttpPost(wxString cmd, wxSocketBase& outs)
bool TLurchServer::Initialization()
{
m_nFreq = GetConfigInt("PingFreq") * 1000; // sec to msec
wxArrayString arr; CreateServersList(arr);
const wxArrayString& arr = GetServersList();
for (size_t i = 0; i < arr.GetCount(); i++)
{
const wxString& strApp = arr[i];
const bool bAutorun = GetConfigBool("Autorun", false, strApp);
if (bAutorun)
StartProcess(strApp);
if (strApp != GetAppName())
{
const bool bAutorun = GetConfigBool("Autorun", false, strApp);
if (bAutorun)
StartProcess(strApp);
}
}
RestartTimer();
const int nFreq = GetConfigInt("PingFreq");
if (nFreq > 0)
{
m_PingTimer.Start(nFreq * 1000); // sec to msec
m_Semaphore.Post(); // GREEN!
}
return true;
}
// Istanziare l'applicazione principale
IMPLEMENT_APP(TLurchServer)
TLurchServer::TLurchServer()
: m_Semaphore(0 /* RED! */, 1 /* mutex like behaviour */)
{ }

View File

@ -1,4 +1,5 @@
#include <wx/wx.h>
#include "wx/mstream.h"
#include <wx/wfstream.h>