Files correlati : lurch.exe Ricompilazione Demo : [ ] Commento : Migliorata gestione restart di Authorization git-svn-id: svn://10.65.10.50/branches/R_10_00@22315 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			724 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			724 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
#include "baseserv.h"
 | 
						|
 | 
						|
#include <wx/config.h>
 | 
						|
#include <wx/filename.h>
 | 
						|
#include <wx/process.h>
 | 
						|
#include <wx/timer.h>
 | 
						|
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
// TLurchServer declaration
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
 | 
						|
//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_hmProcMap;
 | 
						|
  wxSemaphore m_Semaphore;
 | 
						|
  wxTimer m_PingTimer;
 | 
						|
  wxArrayString m_aServers, m_aAutoRun;
 | 
						|
 | 
						|
  DECLARE_EVENT_TABLE();
 | 
						|
 | 
						|
protected:  
 | 
						|
	virtual const wxChar* GetAppName() const;
 | 
						|
  virtual bool Initialization();
 | 
						|
  virtual bool Deinitialization();
 | 
						|
  void OnTimer(wxTimerEvent& evt);
 | 
						|
  void OnEndProcess(wxProcessEvent& evt);
 | 
						|
 | 
						|
	TXmlItem& AddMiniForm(TXmlItem& tr, const wxChar* action, const wxChar* app, const wxChar* prompt) const;
 | 
						|
  void EnumerateVariables(const wxString& strApp, wxArrayString& arr) const;
 | 
						|
 | 
						|
  const wxArrayString& GetServersList() const ;
 | 
						|
  const wxArrayString& GetAutoRunList() const;
 | 
						|
  const TProcessHashMap& GetRunningServers() const { return m_hmProcMap; }
 | 
						|
 | 
						|
  bool PingProcess(const wxString& strApp);
 | 
						|
  bool StopProcess(const wxString& strApp);
 | 
						|
  wxString StartProcess(const wxString& strApp);
 | 
						|
  
 | 
						|
  TXmlItem& AddTableRow(TXmlItem& table, const wxChar* prompt, const wxString& value) const;
 | 
						|
 
 | 
						|
public:
 | 
						|
	void GenerateFile(wxString& strFilename);
 | 
						|
  bool IsMagicName(wxString& strFilename) const;
 | 
						|
  bool IsCgiName(wxString strFilename) const;
 | 
						|
 | 
						|
  void ProcessHttpGet(wxString cmd, wxSocketBase& outs);
 | 
						|
  void ProcessHttpPost(wxString cmd, wxSocketBase& outs);
 | 
						|
 | 
						|
  bool ForgetProcess(const wxString& strApp);
 | 
						|
 | 
						|
  //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();
 | 
						|
};
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////
 | 
						|
// TLurchServer implementation
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
 | 
						|
BEGIN_EVENT_TABLE(TLurchServer, TBaseServerApp)
 | 
						|
  EVT_TIMER(wxID_ANY, TLurchServer::OnTimer)
 | 
						|
  EVT_END_PROCESS(wxID_ANY, TLurchServer::OnEndProcess)
 | 
						|
END_EVENT_TABLE()
 | 
						|
 | 
						|
bool TLurchServer::PingProcess(const wxString& strApp)
 | 
						|
{
 | 
						|
  bool bPinged = false;
 | 
						|
 | 
						|
  const unsigned short nPort = GetConfigInt("Port", 0, strApp);
 | 
						|
  if (nPort > 0)
 | 
						|
  {
 | 
						|
    int nTimeOut = m_PingTimer.GetInterval()/3; // msec
 | 
						|
    if (nTimeOut < 1000) nTimeOut = 1000; else
 | 
						|
    if (nTimeOut > 5000) nTimeOut = 5000;
 | 
						|
 | 
						|
    wxIPV4address ipAddress;
 | 
						|
    //ipAddress.AnyAddress();  // NON funziona con ESET
 | 
						|
    ipAddress.LocalHost();     // Pare funzionare sempre
 | 
						|
    ipAddress.Service(nPort);
 | 
						|
    wxSocketClient sSock(wxSOCKET_NOWAIT);
 | 
						|
    sSock.Connect(ipAddress, false);
 | 
						|
    if (sSock.WaitOnConnect(0, 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))
 | 
						|
      {
 | 
						|
        ::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, wxT("PONG"), 4) == 0;
 | 
						|
        sSock.Discard(); // Tralascia ulteriori dati in arrivo
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        wxString strMsg;
 | 
						|
        strMsg << _("Ping Host - ") << ipAddress.Hostname() << ":" << nPort << _(" - Write Error ") << sSock.LastError() ;
 | 
						|
        WriteLog(strMsg);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      wxString strMsg;
 | 
						|
      strMsg << _("Ping Host - ") << ipAddress.Hostname() << ":" << nPort << _(" - Connection Error ") << sSock.LastError() ;
 | 
						|
      WriteLog(strMsg);
 | 
						|
    }
 | 
						|
    /*
 | 
						|
    wxDatagramSocket dSock(ipAddress, wxSOCKET_NOWAIT);
 | 
						|
    ipAddress.Service(1884);
 | 
						|
    dSock.SendTo(ipAddress, "PING\n", 5);
 | 
						|
    */
 | 
						|
  }
 | 
						|
 
 | 
						|
  return bPinged;
 | 
						|
}
 | 
						|
 | 
						|
void TLurchServer::OnTimer(wxTimerEvent& evt)
 | 
						|
{
 | 
						|
  const wxSemaError se = IsRunning() ? m_Semaphore.TryWait() : wxSEMA_MISC_ERROR;
 | 
						|
  if (se == wxSEMA_NO_ERROR)
 | 
						|
  {
 | 
						|
    const wxArrayString& aServers = GetAutoRunList();
 | 
						|
    const size_t nServers = aServers.GetCount();
 | 
						|
    if (nServers > 0) // Is anybody out there?
 | 
						|
    {
 | 
						|
      const int nRandomIndex = ::rand() % nServers;
 | 
						|
      const wxString& strApp = aServers[nRandomIndex]; // Usually "Authorization"
 | 
						|
      if (!PingProcess(strApp))
 | 
						|
      {
 | 
						|
        if (!strApp.IsEmpty()) // Dummy test
 | 
						|
        {
 | 
						|
     			const wxSingleInstanceChecker sic(strApp);
 | 
						|
          if (sic.IsAnotherRunning())
 | 
						|
          {
 | 
						|
            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();
 | 
						|
  }
 | 
						|
  else
 | 
						|
    evt.Skip();
 | 
						|
}
 | 
						|
 | 
						|
void TLurchServer::OnEndProcess(wxProcessEvent& evt)
 | 
						|
{
 | 
						|
  for (TProcessHashMap::const_iterator it = m_hmProcMap.begin(); it != m_hmProcMap.end(); ++it)
 | 
						|
  {
 | 
						|
    const wxProcess* p = it->second;
 | 
						|
    if (p->GetPid() == evt.GetPid())
 | 
						|
    {
 | 
						|
      const wxString name = it->first;
 | 
						|
      ForgetProcess(name);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
const wxChar* TLurchServer::GetAppName() const
 | 
						|
{	return wxT("Lurch"); }
 | 
						|
 | 
						|
const wxArrayString& TLurchServer::GetServersList() const
 | 
						|
{
 | 
						|
  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;
 | 
						|
  		  ((wxArrayString&)m_aServers).Add(str);
 | 
						|
  			aperta = strchr(chiusa+1, '[');
 | 
						|
  		}
 | 
						|
  		else
 | 
						|
  			break;
 | 
						|
  	}
 | 
						|
  }
 | 
						|
  return m_aServers;
 | 
						|
}
 | 
						|
 | 
						|
const wxArrayString& TLurchServer::GetAutoRunList() const
 | 
						|
{
 | 
						|
  if (m_aAutoRun.IsEmpty())
 | 
						|
  {
 | 
						|
    const wxArrayString& as = GetServersList();
 | 
						|
    for (size_t i = 0; i < as.GetCount(); i++)
 | 
						|
    {
 | 
						|
      const bool bAutorun = GetConfigBool("Autorun", false, as[i]);
 | 
						|
      if (bAutorun)
 | 
						|
        ((wxArrayString&)m_aAutoRun).Add(as[i]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return m_aAutoRun;
 | 
						|
}
 | 
						|
 | 
						|
TXmlItem& TLurchServer::AddMiniForm(TXmlItem& tr, const wxChar* action, const wxChar* app, const wxChar* prompt) const
 | 
						|
{
 | 
						|
	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");
 | 
						|
	name.SetAttr("type", "hidden"); name.SetAttr("name", "App");
 | 
						|
	name.SetAttr("value", app);
 | 
						|
 | 
						|
	TXmlItem& submit = form.AddChild("input");
 | 
						|
	submit.SetAttr("type", "submit"); 
 | 
						|
	submit.SetAttr("value", prompt); 
 | 
						|
  return submit;
 | 
						|
}
 | 
						|
 | 
						|
 TXmlItem& TLurchServer::AddTableRow(TXmlItem& table, const wxChar* prompt, const wxString& value) const
 | 
						|
 {
 | 
						|
   TXmlItem& tr = table.AddChild("tr");
 | 
						|
   tr.AddChild("td").AddEnclosedText(prompt);
 | 
						|
   tr.AddChild("td").AddEnclosedText(value);
 | 
						|
   return tr;
 | 
						|
 }
 | 
						|
 | 
						|
void TLurchServer::GenerateFile(wxString& strFilename)
 | 
						|
{
 | 
						|
	TXmlItem html; 
 | 
						|
	TXmlItem& body = CreatePageBody(html);
 | 
						|
 | 
						|
	if (strFilename == "index")
 | 
						|
	{
 | 
						|
		TXmlItem& table = body.AddChild("table");
 | 
						|
		table.SetAttr("border", "1"); table.SetAttr("width", "100%");
 | 
						|
		strFilename = GetTempFilename();
 | 
						|
		const wxString strLurchName = GetAppName();
 | 
						|
 | 
						|
    const wxArrayString& arr = GetServersList();
 | 
						|
		for (size_t i = 0; i < arr.GetCount(); i++)
 | 
						|
		{
 | 
						|
      const wxString& strApp = arr[i];
 | 
						|
			const bool bLurch = strApp == strLurchName;
 | 
						|
      const wxString strHost = GetConfigString("Host", wxGetHostName(), strApp); 
 | 
						|
			const int nPort = GetConfigInt("Port", 3883, strApp); 
 | 
						|
      const wxString strIcon = GetConfigString("Icon", "euro.gif", strApp); 
 | 
						|
 | 
						|
			const wxSingleInstanceChecker sic(strApp);
 | 
						|
			const bool bRunning = sic.IsAnotherRunning();
 | 
						|
 | 
						|
			TXmlItem& tr = table.AddChild("tr");
 | 
						|
			TXmlItem& td0 = tr.AddChild("td");
 | 
						|
			td0.SetAttr("width", "10%"); td0.SetAttr("align", "center");
 | 
						|
			TXmlItem& a = td0.AddChild("a");
 | 
						|
			if (!bLurch && bRunning)
 | 
						|
			{
 | 
						|
				a.SetAttr("href", wxString::Format("http://%s:%d/index.htm", strHost.c_str(), nPort));
 | 
						|
				a.SetAttr("target", "_blank");
 | 
						|
			} 
 | 
						|
 			TXmlItem& img = a.AddChild("img");
 | 
						|
			img.SetAttr("src", strIcon); img.SetAttr("border", 0L); img.SetAttr("alt", arr[i]);
 | 
						|
 | 
						|
      const bool bAutoRun = bLurch || GetAutoRunList().Index(arr[i]) != wxNOT_FOUND;
 | 
						|
      TXmlItem& buttStart = AddMiniForm(tr, "start.cgi", arr[i], _("Start"));
 | 
						|
      if (bRunning /* || bAutoRun */)
 | 
						|
         buttStart.SetAttr(wxT("type"), wxT("hidden"));
 | 
						|
 | 
						|
      TXmlItem& buttStop = AddMiniForm(tr, "kill.cgi", arr[i], _("Stop"));
 | 
						|
      if (!bLurch && (!bRunning || bAutoRun))
 | 
						|
         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)
 | 
						|
			{
 | 
						|
				a3.SetAttr("href", wxString::Format("http://%s:%d/index.htm", strHost.c_str(), nPort)); 
 | 
						|
				a3.SetAttr("target", "_blank"); 
 | 
						|
      }
 | 
						|
     	a3 << arr[i] << " Server";
 | 
						|
		}
 | 
						|
 | 
						|
    body.AddChild("hr");
 | 
						|
    TXmlItem& panel = body.AddChild("table");
 | 
						|
    panel.SetAttr("border", "1"); panel.SetAttr("width", "100%");
 | 
						|
    panel.AddChild("caption").AddEnclosedText("Options");
 | 
						|
    
 | 
						|
    AddTableRow(panel, wxT("Working directory"), wxGetCwd());
 | 
						|
 | 
						|
    wxString strHost; strHost << wxGetHostName() << wxT(":") << GetDefaultPort();
 | 
						|
    AddTableRow(panel, wxT("Host Name"), strHost);
 | 
						|
    
 | 
						|
    int y, v, t, p; GetVersionInfo(y, v, t, p);
 | 
						|
    wxString strVer; strVer.Printf(wxT("%d.%d.%d"), v, t, p);
 | 
						|
    AddTableRow(panel, wxT("Version"), strVer);
 | 
						|
 | 
						|
    wxString strFreq; strFreq << m_PingTimer.GetInterval()/1000;
 | 
						|
    AddTableRow(panel, wxT("Ping Frequency"), strFreq);
 | 
						|
 | 
						|
		html.Save(strFilename);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool TLurchServer::IsMagicName(wxString& strFilename) const
 | 
						|
{
 | 
						|
  wxString strName;
 | 
						|
	wxSplitPath(strFilename, NULL, &strName, NULL);
 | 
						|
  strName.MakeLower();
 | 
						|
	if (strName == "index")
 | 
						|
	{
 | 
						|
		strFilename = strName;
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
	if (strName == "log")
 | 
						|
	{
 | 
						|
		strFilename = GetLogFileName();
 | 
						|
	}
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool TLurchServer::IsCgiName(wxString strFilename) const
 | 
						|
{
 | 
						|
	const int q = strFilename.Find('?');
 | 
						|
	if (q > 0)
 | 
						|
		strFilename.Truncate(q);
 | 
						|
 | 
						|
	wxString strExt;
 | 
						|
	wxSplitPath(strFilename, NULL, NULL, &strExt);
 | 
						|
  strExt.MakeLower();
 | 
						|
	return strExt == "cgi" || strExt == "exe";
 | 
						|
}
 | 
						|
 | 
						|
wxString TLurchServer::StartProcess(const wxString& strApp)
 | 
						|
{
 | 
						|
  bool ok = false;
 | 
						|
 | 
						|
  wxString strMessage;
 | 
						|
	if (!strApp.IsEmpty())
 | 
						|
	{
 | 
						|
  	const wxSingleInstanceChecker sic(strApp);
 | 
						|
		ok = !sic.IsAnotherRunning();
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (ok)
 | 
						|
	{
 | 
						|
		const wxString strRun = GetConfigString("Run", "", strApp);
 | 
						|
		if (wxFileExists(strRun))
 | 
						|
		{
 | 
						|
      wxFileName fnPath; 
 | 
						|
      fnPath.SetPath(GetServerPath());
 | 
						|
      fnPath.SetFullName(strRun);
 | 
						|
 | 
						|
      wxProcess* pProcess = wxProcess::Open(fnPath.GetFullPath());
 | 
						|
			if (pProcess == NULL)
 | 
						|
      {
 | 
						|
				strMessage.Printf(_("Can't run %s executable (%s)"), strApp.c_str(), strRun.c_str());
 | 
						|
      }
 | 
						|
			else
 | 
						|
      {
 | 
						|
        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());
 | 
						|
	}
 | 
						|
	else
 | 
						|
		strMessage.Printf(_("%s il already running"), strApp.c_str());
 | 
						|
 | 
						|
  if (strMessage.IsEmpty())
 | 
						|
    WriteLog(strApp + _(" started."));
 | 
						|
  else
 | 
						|
    WriteLog(strMessage);
 | 
						|
 | 
						|
  return strMessage;
 | 
						|
}
 | 
						|
 | 
						|
void TLurchServer::ProcessFormStart(const THashTable& args, wxSocketBase& sock)
 | 
						|
{
 | 
						|
  const wxString strApp = args.Get("App");
 | 
						|
	if (!strApp.IsEmpty()) // Dummy test
 | 
						|
	{
 | 
						|
    const wxString strMessage = StartProcess(strApp);
 | 
						|
    if (strMessage.IsEmpty())
 | 
						|
      MessageBox(_("Server Started"), strApp, sock);
 | 
						|
    else
 | 
						|
      MessageBox(_("ERROR"), strMessage, sock);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
bool TLurchServer::ForgetProcess(const wxString& strApp)
 | 
						|
{
 | 
						|
  bool ok = m_hmProcMap.erase(strApp) != 0;
 | 
						|
  if (ok)
 | 
						|
    WriteLog(strApp + _(" terminated."));
 | 
						|
  return ok;
 | 
						|
}
 | 
						|
 | 
						|
bool TLurchServer::StopProcess(const wxString& strApp)
 | 
						|
{
 | 
						|
  if (strApp != GetAppName())
 | 
						|
  {
 | 
						|
    const wxSingleInstanceChecker sic(strApp);
 | 
						|
    if (!sic.IsAnotherRunning()) // E' belle che muorto!
 | 
						|
      return ForgetProcess(strApp); 
 | 
						|
  }
 | 
						|
  else
 | 
						|
    return false;
 | 
						|
 
 | 
						|
	const wxString strHost = GetConfigString("Host", "localhost", strApp);
 | 
						|
	const int nPort = GetConfigInt("Port", 0, strApp);
 | 
						|
	if (nPort > 0)
 | 
						|
	{
 | 
						|
		wxIPV4address addr;
 | 
						|
		addr.Hostname(strHost);
 | 
						|
		addr.Service(nPort);
 | 
						|
 | 
						|
		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 (addr.IsLocalHost())
 | 
						|
			{
 | 
						|
				const wxSingleInstanceChecker sic(strApp);
 | 
						|
        int i;
 | 
						|
				for (i = 5; i >= 0 && sic.IsAnotherRunning(); i--)
 | 
						|
					wxSleep(1);
 | 
						|
        // Se le buone non hanno funzionato ... passo alle cattive
 | 
						|
        if (i < 0)
 | 
						|
        {
 | 
						|
          wxProcess* p = m_hmProcMap[strApp];
 | 
						|
          if (p != NULL)
 | 
						|
          {
 | 
						|
            p->Kill(p->GetPid());
 | 
						|
            return ForgetProcess(strApp);
 | 
						|
          }
 | 
						|
        }
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void TLurchServer::ProcessFormStop(const THashTable& args, wxSocketBase& sock)
 | 
						|
{
 | 
						|
  if (m_Semaphore.Wait() == wxSEMA_NO_ERROR)
 | 
						|
  {
 | 
						|
    const wxString strApp = args.Get("App");
 | 
						|
    if (strApp == GetAppName() || strApp.IsEmpty()) // Stop myself!
 | 
						|
    {  
 | 
						|
      wxString strCmd = wxT("stop.cgi"); // Exits main loop;
 | 
						|
      TBaseServerApp::CanProcessCommand(strCmd, sock);
 | 
						|
    }
 | 
						|
    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());
 | 
						|
	wxString strParagraph = wxString::Format("[%s]", strApp.c_str());
 | 
						|
	wxString str;
 | 
						|
 | 
						|
	bool bFound = false;
 | 
						|
	while (inf.Ok())
 | 
						|
	{
 | 
						|
    inf >> str;
 | 
						|
    if (str == strParagraph)
 | 
						|
		{
 | 
						|
			bFound = true;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (bFound)
 | 
						|
	{
 | 
						|
		while (inf.Ok())
 | 
						|
		{
 | 
						|
			inf >> str;
 | 
						|
			if (str.IsEmpty() || str[0u] == '[')
 | 
						|
				break;
 | 
						|
			const int nEqual = str.Find('=');
 | 
						|
      if (nEqual > 0)
 | 
						|
			{
 | 
						|
				str.Truncate(nEqual);
 | 
						|
				str.Trim(false);
 | 
						|
				str.Trim(true);
 | 
						|
				arr.Add(str);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		arr.Sort();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void TLurchServer::ProcessFormConfig(const THashTable& args, wxSocketBase& sock)
 | 
						|
{
 | 
						|
  const wxString strApp = args.Get("App");
 | 
						|
  wxArrayString arr;
 | 
						|
	EnumerateVariables(strApp, arr);
 | 
						|
 | 
						|
	TXmlItem html; 
 | 
						|
	TXmlItem& body = CreatePageBody(html);
 | 
						|
 | 
						|
  TXmlItem& form = body.AddChild("form");
 | 
						|
  form.SetAttr("action", "update.cgi").SetAttr("method", "post");
 | 
						|
	
 | 
						|
	TXmlItem& table = form.AddChild("table").SetAttr("width", "100%").SetAttr("border", "1");
 | 
						|
	table.AddChild("caption").AddChild("h2") << strApp;
 | 
						|
	TXmlItem& thead = table.AddChild("thead");
 | 
						|
	thead.AddChild("th").SetAttr("width", "15%") << "Property";
 | 
						|
	thead.AddChild("th").SetAttr("width", "85%") << "Value";
 | 
						|
 | 
						|
	for (size_t v = 0; v < arr.GetCount(); v++)
 | 
						|
	{
 | 
						|
		TXmlItem& tr = table.AddChild("tr");
 | 
						|
		tr.AddChild("td") << arr[v];
 | 
						|
		TXmlItem& input = tr.AddChild("td").AddChild("input");
 | 
						|
		input.SetAttr("type", "text"); input.SetAttr("name", arr[v]);
 | 
						|
		input.SetAttr("size", "80"); input.SetAttr("maxlength", "256");
 | 
						|
		input.SetAttr("value", GetConfigString(arr[v], "", strApp));
 | 
						|
	}
 | 
						|
 | 
						|
	TXmlItem& app = form.AddChild("input").SetAttr("type", "hidden");
 | 
						|
	app.SetAttr("name", "App"); app.SetAttr("value", strApp);
 | 
						|
 | 
						|
	TXmlItem& submit = form.AddChild("br").AddChild("center").AddChild("input");
 | 
						|
	submit.SetAttr("type", "submit"); submit.SetAttr("value", "Update Parameters");
 | 
						|
 | 
						|
	body.AddChild("br");
 | 
						|
	AddLinkButton(body.AddChild("center"), "Return to main page", "/");
 | 
						|
 | 
						|
	const wxString strFilename = GetTempFilename();
 | 
						|
  html.Save(strFilename);
 | 
						|
  SendFile(strFilename, sock);
 | 
						|
}
 | 
						|
 | 
						|
void TLurchServer::ProcessFormUpdate(THashTable& args, wxSocketBase& sock)
 | 
						|
{
 | 
						|
  const wxString strApp = args.Get("App");
 | 
						|
	args.BeginFind();
 | 
						|
  for (wxHashTable::Node* pNode = args.Next(); pNode; pNode = args.Next())
 | 
						|
	{
 | 
						|
		const wxString strKey = pNode->GetKeyString();
 | 
						|
		if (strKey != "App")
 | 
						|
		{
 | 
						|
		  const wxString strVal = args.Get(strKey);
 | 
						|
		  SetConfigString(strKey, strVal, strApp);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	const wxString msg = wxString::Format("%s parameters updated", strApp.c_str());
 | 
						|
  MessageBox("Success!", msg, sock);
 | 
						|
}
 | 
						|
 | 
						|
void TLurchServer::CallCgi(wxString& strFileName, wxSocketBase& sock)
 | 
						|
{
 | 
						|
	wxString strName, strExt, strArgs;
 | 
						|
	const int q = strFileName.Find('?');
 | 
						|
	if (q > 0)
 | 
						|
	{
 | 
						|
		strArgs = strFileName.Mid(q+1);
 | 
						|
		strFileName.Truncate(q);
 | 
						|
	}
 | 
						|
	wxSplitPath(strFileName, NULL, &strName, &strExt);
 | 
						|
 | 
						|
	THashTable hashArgs(13);
 | 
						|
  ParseArguments(strArgs, hashArgs);
 | 
						|
 | 
						|
	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")
 | 
						|
			ProcessFormUpdate(hashArgs, sock);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void TLurchServer::ProcessHttpGet(wxString cmd, wxSocketBase& outs)
 | 
						|
{
 | 
						|
  const int stop = cmd.Find(" HTTP");
 | 
						|
	wxString str = cmd.Mid(4, stop-4).Trim();
 | 
						|
 | 
						|
	if (str == "/")
 | 
						|
		str += "index.htm";
 | 
						|
	wxString strFilename = GetDocumentRoot() + str;
 | 
						|
 | 
						|
 	if (IsCgiName(strFilename))
 | 
						|
	  CallCgi(strFilename, outs);
 | 
						|
	else
 | 
						|
	{
 | 
						|
	  if (IsMagicName(strFilename))
 | 
						|
		  GenerateFile(strFilename);
 | 
						|
	  SendFile(strFilename, outs);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void TLurchServer::ProcessHttpPost(wxString cmd, wxSocketBase& outs)
 | 
						|
{
 | 
						|
  const int stop = cmd.Find(" HTTP");
 | 
						|
	wxString strFileName = cmd.Mid(5, stop-5).Trim();
 | 
						|
 | 
						|
	wxString strName, args;
 | 
						|
	wxSplitPath(strFileName, NULL, &strName, NULL);
 | 
						|
 | 
						|
	const int pos = cmd.Find("\r\n\r\n");
 | 
						|
	if (pos > 0)
 | 
						|
	  args = cmd.Mid(pos+4);
 | 
						|
 | 
						|
	THashTable hashArgs(17);
 | 
						|
  ParseArguments(args, hashArgs);
 | 
						|
 | 
						|
	if (strName == "update")
 | 
						|
		ProcessFormUpdate(hashArgs, outs);
 | 
						|
}
 | 
						|
 | 
						|
bool TLurchServer::Initialization()
 | 
						|
{
 | 
						|
  const wxArrayString& arr = GetAutoRunList();
 | 
						|
  const size_t nAuto = arr.GetCount();
 | 
						|
  if (nAuto > 0)
 | 
						|
  {
 | 
						|
  	for (size_t i = 0; i < nAuto; i++)
 | 
						|
      StartProcess(arr[i]); 
 | 
						|
    const int nFreq = GetConfigInt("PingFreq");
 | 
						|
    if (nFreq > 0)
 | 
						|
      m_PingTimer.Start(nFreq * 1000); // sec to msec
 | 
						|
  }  
 | 
						|
  m_Semaphore.Post(); // GREEN!
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
bool TLurchServer::Deinitialization()
 | 
						|
{
 | 
						|
  m_PingTimer.Stop(); // Stop ping process!
 | 
						|
 | 
						|
  // kill all autorun processes even if I didn't start them
 | 
						|
  const wxArrayString& ar = GetAutoRunList();
 | 
						|
  for (size_t i = 0; i < ar.GetCount(); i++)
 | 
						|
    StopProcess(ar[i]);
 | 
						|
 | 
						|
  // kill all still running (die hard) processes
 | 
						|
  const TProcessHashMap& hmServers = GetRunningServers();  
 | 
						|
  if (!hmServers.empty())
 | 
						|
  {
 | 
						|
    // Fill a safe array of names before killing the processes stored in the hash map
 | 
						|
    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]);
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
// Istanziare l'applicazione principale
 | 
						|
 | 
						|
IMPLEMENT_APP(TLurchServer)
 | 
						|
 | 
						|
TLurchServer::TLurchServer() 
 | 
						|
            : m_Semaphore(0 /* RED! */, 1 /* mutex like behaviour */)
 | 
						|
{ }
 |