///////////////////////////////////////////////////////////////////////////// // Name: BaseServ.cpp // Purpose: Simple base Server // Author: Guy // Modified by: // Created: 21/08/2002 // Copyright: (c) 2002 Guy // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ========================================================================== // declarations // ========================================================================== // -------------------------------------------------------------------------- // headers // -------------------------------------------------------------------------- #include #include "baseserv.h" #include #include #include #include #include #include #include #ifndef __WXMSW__ #include #endif /////////////////////////////////////////////////////////// // Utilities /////////////////////////////////////////////////////////// IMPLEMENT_ABSTRACT_CLASS(TBaseServerApp, wxApp) TBaseServerApp& GetServerApp() { return *wxStaticCast(wxTheApp, TBaseServerApp); } wxString Date2String(const wxDateTime& date) { return date.Format("%d-%m-%Y"); } wxDateTime String2Date(const wxString& str) { int d, m, y; sscanf(str, "%d-%d-%d", &d, &m, &y); wxDateTime date(d, wxDateTime::Month(m-1), y); return date; } wxSocketBase& operator<<(wxSocketBase& outf, const wxChar* str) { if (str && *str) outf.Write(str, (wxUint32)wxStrlen(str)); return outf; } wxSocketBase& operator<<(wxSocketBase& outf, wxString str) { if (!str.IsEmpty()) outf.Write(str, (wxUint32)str.Length()); return outf; } wxSocketBase& operator<<(wxSocketBase& outf, size_t num) { return outf << wxString::Format("%u", num); } // -------------------------------------------------------------------------- // classes // -------------------------------------------------------------------------- /////////////////////////////////////////////////////////// // THashTable /////////////////////////////////////////////////////////// void THashTable::Put(const wxString& key, const wxString& value) { THashString* entry = new THashString(value); m_Hash.Put(key, entry); } wxString THashTable::Get(const wxChar* key) const { wxString strValue; THashString* str = (THashString*)m_Hash.Get(key); if (str != NULL) strValue = str->m_str; return strValue; } THashTable::THashTable(size_t size) : m_Hash(wxKEY_STRING, size) { m_Hash.DeleteContents(true); } #ifdef wxHAS_TASK_BAR_ICON /////////////////////////////////////////////////////////// // TTaskbarIcon /////////////////////////////////////////////////////////// BEGIN_EVENT_TABLE(TTaskBarIcon, wxTaskBarIcon) EVT_TASKBAR_LEFT_DOWN(TTaskBarIcon::OnTaskBarClick) END_EVENT_TABLE() void TTaskBarIcon::OnTaskBarClick(wxTaskBarIconEvent& WXUNUSED(e)) { wxString strURL; // wxIPV4address addr; addr.AnyAddress(); // addr.Service(GetServerApp().GetDefaultPort()); // url << addr.Hostname() << ":" << addr.Service(); strURL << "http://127.0.0.1:" << GetServerApp().GetDefaultPort(); wxLaunchDefaultBrowser(strURL); } void TTaskBarIcon::Init() { const TBaseServerApp& a = GetServerApp(); wxIcon icon; const wxString strIcon = a.GetConfigString("Icon"); if (wxFileExists(strIcon)) { wxInitAllImageHandlers(); wxImage img(strIcon); img.Rescale(32,32/*,wxIMAGE_QUALITY_HIGH*/); const wxBitmap bmp(img); icon.CopyFromBitmap(bmp); } else icon.LoadFile("soap", wxBITMAP_TYPE_ICO_RESOURCE); SetIcon(icon, a.GetAppName()); } #endif /////////////////////////////////////////////////////////// // TBaseServerApp /////////////////////////////////////////////////////////// enum { SERVER_ID = 1001, SOCKET_ID = 1002, DATAGRAM_ID = 1003, }; BEGIN_EVENT_TABLE(TBaseServerApp, wxApp) EVT_SOCKET(SERVER_ID, TBaseServerApp::OnServerEvent) EVT_SOCKET(SOCKET_ID, TBaseServerApp::OnSocketEvent) EVT_SOCKET(DATAGRAM_ID, TBaseServerApp::OnDatagramEvent) EVT_IDLE(TBaseServerApp::OnIdle) END_EVENT_TABLE() void TBaseServerApp::WriteLog(const wxChar* str) const { if (m_log != NULL) { //raccatta data ed ora const wxString strNow = wxNow(); *m_log << strNow << " " << str << endl; } } wxString TBaseServerApp::GetTempFilename(const wxChar * ext) { wxString strTmp; if (m_strTempDir.IsEmpty()) { const wxString strPrefix = "Srv"; ::wxGetTempFileName(strPrefix, strTmp); ::wxRemoveFile(strTmp); (wxString&)m_strTempDir << ::wxPathOnly(strTmp) << "/"; } strTmp = m_strTempDir; strTmp += wxString::Format("%s_%d.%s", GetAppName(), m_nTmpCounter, ext); m_nTmpCounter++; if (m_nTmpCounter >= 32) m_nTmpCounter = 0; return strTmp; } TXmlItem& TBaseServerApp::AddLogo(TXmlItem& tr) const { TXmlItem& td = tr.AddChild("td"); td.SetAttr("width", "15%"); td.SetAttr("align", "center"); TXmlItem& a = td.AddChild("a"); a.SetAttr("href", "/index.htm"); const wxString gif = GetConfigString("Icon", "euro.gif"); TXmlItem& img = a.AddChild("img"); img.SetAttr("src", gif); img.SetAttr("border", "0"); img.SetAttr("alt", "Return to Home Page"); return td; } TXmlItem& TBaseServerApp::CreatePageBody(TXmlItem& html, wxString header) const { if (header.IsEmpty()) header << GetAppName() << " Server"; html.SetTag("html"); TXmlItem& head = html.AddChild("head"); TXmlItem& meta1 = head.AddChild("meta"); meta1.SetAttr("name", "GENERATOR"); meta1.SetAttr("content", GetAppName()); TXmlItem& meta2 = head.AddChild("meta"); meta2.SetAttr("HTTP-EQUIV", "Content-Type"); meta2.SetAttr("content", "text/html; charset=iso-8859-1"); head.AddChild("title") << header; TXmlItem& body = html.AddChild("body"); body.SetAttr("bgcolor", "#EFCEAD"); if (IsRunning()) body.SetAttr("background", "back.gif"); TXmlItem& title = body.AddChild("table"); title.SetAttr("border", "5"); title.SetAttr("width", "100%"); TXmlItem& title_tr = title.AddChild("tr"); if (IsRunning()) AddLogo(title_tr); TXmlItem& td1 = title_tr.AddChild("td"); td1.AddChild("h1").AddChild("center") << header; if (IsRunning()) AddLogo(title_tr); body.AddChild("br"); return body; } TXmlItem& TBaseServerApp::AddLinkButton(TXmlItem& body, const wxChar* strCaption, const wxChar* strHref) const { TXmlItem& table = body.AddChild("table"); table.SetAttr("border", "2"); table.SetAttr("bgcolor", "#C0C0C0"); TXmlItem& td = table.AddChild("tr").AddChild("td"); td.SetAttr("align", "center"); td.AddChild("a").SetAttr("href", strHref) << strCaption; return table; } void TBaseServerApp::MessageBox(const wxChar* caption, const wxChar* msg, wxSocketBase& outs) { TXmlItem html; TXmlItem& body = CreatePageBody(html); TXmlItem& table = body.AddChild("center").AddChild("table"); table.SetAttr("width", "70%"); table.SetAttr("border", "2"); table.AddChild("caption").AddChild("h2") << caption; TXmlItem& td0 = table.AddChild("tr").AddChild("td"); td0.SetAttr("align", "justify"); td0.AddChild("h3") << msg; TXmlItem& td1 = table.AddChild("tr").AddChild("td"); td1.SetAttr("align", "center"); AddLinkButton(td1, "Return to main page", "index.htm"); const wxString strTmp = GetTempFilename(); html.Save(strTmp); SendFile(strTmp, outs); } bool TBaseServerApp::CanProcessCommand(wxString& cmd, wxSocketBase& outs) { if (cmd.Find("stop.cgi") >= 0) { m_bRunning = false; // Disable gif on title if (outs.IsOk()) MessageBox("Warning!", "Server Stopped", outs); ExitMainLoop(); return false; } return true; } void TBaseServerApp::SendContent(wxFileInputStream& inf, wxSocketBase& sock) { const size_t nSize = inf.GetSize(); if (m_bLogVerbose) WriteLog(wxString::Format("Sending %lu bytes", nSize)); const size_t BUF_TEMP_SIZE = 1024*1024; // was 1024*16 char* buf = new char[BUF_TEMP_SIZE]; size_t bytes = BUF_TEMP_SIZE; size_t nTotalWritten = 0; while (bytes == BUF_TEMP_SIZE) { bytes = inf.Read(buf, bytes).LastRead(); size_t nWritten = sock.Write(buf, wxUint32(bytes)).LastCount(); nTotalWritten += nWritten; } delete buf; if (nTotalWritten < nSize) WriteLog(wxString::Format("I sent %lu of %lu bytes only.", nTotalWritten, nSize)); } void TBaseServerApp::SendFile(wxString strFilename, wxSocketBase& sock) { const bool bFound = wxFileExists(strFilename); if (!bFound) { const wxString strTmp = GetTempFilename(); if (!strTmp.IsEmpty()) { TXmlItem html; TXmlItem& body = CreatePageBody(html); body.AddChild("h1") << "Sorry: File not found!"; body.AddChild("br"); body.AddChild("h2") << strFilename; html.Save(strTmp); } strFilename = strTmp; } wxString strType; wxSplitPath(strFilename, NULL, NULL, &strType); wxFileType* type = wxTheMimeTypesManager->GetFileTypeFromExtension(strType); if (type != NULL) type->GetMimeType(&strType); else strType = "text/plain"; const wxDateTime date = ::wxFileModificationTime(strFilename); wxFileInputStream inf(strFilename); const size_t nSize = inf.GetSize(); if (bFound) sock << "HTTP/1.1 200 OK\n"; else sock << "HTTP/1.1 401 Not found\n"; sock << "Server: " << GetAppName() << "\n"; sock << "Host: " << wxGetFullHostName() << "\n"; if (bFound && m_bRunning) sock << "Connection: keep-alive\n"; else sock << "Connection: close\n"; sock << "Content-Type: " << strType << "\n"; sock << "Content-Length: " << nSize << "\n"; sock << "Date: " << date.Format("%#c") << "\n"; wxDateTime dtFraUnPo = wxDateTime::Now(); const wxTimeSpan minuto(0, 1, 0); // Zero ore, Un minuto, Zero secondi dtFraUnPo += minuto; sock << "Expires: " << dtFraUnPo.Format("%#c") << "\n"; sock << "\n"; SendContent(inf, sock); } void TBaseServerApp::SoapProcessMethod(const TXmlItem& WXUNUSED(xmlMethod), TXmlItem& WXUNUSED(xmlAnswer)) { } void TBaseServerApp::ProcessSoapCommand(wxString cmd, wxSocketBase& sock) { TXmlItem xmlEnvelope; xmlEnvelope.SetTag("SOAP-ENV:Envelope"); TXmlItem& xmlBody = xmlEnvelope.AddChild("SOAP-ENV:Body"); const int soapstart = cmd.Find(" 0) { const size_t soaplen = cmd.length() - soapstart; const char* buff = (const char*)cmd; buff += soapstart; wxMemoryInputStream input(buff, soaplen); TXmlItem query; if (query.Read(input)) { const TXmlItem* pxmlBody = query.FindFirst("SOAP-ENV:Body"); if (pxmlBody != NULL) for (int m = 0; ; m++) { const TXmlItem* pxmlMethod = pxmlBody->GetChild(m); if (pxmlMethod == NULL) break; if (pxmlMethod->GetTag().StartsWith("m:")) { wxString str = pxmlMethod->GetTag(); str += "Result"; TXmlItem& xmlAnswer = xmlBody.AddChild(str); SoapProcessMethod(*pxmlMethod, xmlAnswer); } } } } const wxString strResult = xmlEnvelope.AsString(); sock << "HTTP/1.1 200 OK" << endl; sock << "Connection: keep-alive" << endl; sock << "Content-Length: " << strResult.Length() << endl; sock << "Content-Type: text/xml; charset=utf-8" << endl; sock << "Date: " << wxDateTime::Now().Format("%#c") << endl; sock << "Server: " << GetAppName() << endl; sock << "Host: " << wxGetFullHostName() << endl; sock << endl; sock << strResult; } void TBaseServerApp::ProcessHttpGet(wxString cmd, wxSocketBase& sock) { const int stop = cmd.Find(" HTTP"); wxString str = cmd.Mid(4, stop-4).Trim(); if (str == "/") str += "index.htm"; wxString strFilename = GetDocumentRoot() + str; SendFile(strFilename, sock); } void TBaseServerApp::ProcessFormCommand(wxString WXUNUSED(cmd), wxSocketBase& WXUNUSED(sock)) { } void TBaseServerApp::SendNotModifiedFile(wxSocketBase& sock) { sock << "HTTP/1.1 304 Not Modified\n"; sock << "Date: " << wxDateTime::Now().Format("%#c") << "\n"; sock << "Server: " << GetAppName() << "\n"; sock << "Connection: close\n"; } const wxChar* TBaseServerApp::GetAppName() const { // Pure virtual function return "Server"; } bool TBaseServerApp::ProcessCommand(wxString cmd, wxSocketBase& outs) { bool bProcessed = true; if (cmd.StartsWith("POST ")) { if (cmd.Find("SOAPAction") > 0) ProcessSoapCommand(cmd, outs); else ProcessFormCommand(cmd, outs); } else if (cmd.StartsWith("GET ")) ProcessHttpGet(cmd, outs); else if (cmd.StartsWith("PING")) outs << "PONG\n"; else bProcessed = false; return bProcessed; } void TBaseServerApp::OnServerEvent(wxSocketEvent& e) { // Accept new connection if there is one in the pending // connections queue, else exit. We use Accept(FALSE) for // non-blocking accept (although if we got here, there // should ALWAYS be a pending connection). switch(e.GetSocketEvent()) { case wxSOCKET_CONNECTION: { wxSocketBase* sock = m_server->Accept(false); if (sock != NULL) { sock->SetEventHandler(*this, SOCKET_ID); sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); sock->Notify(true); if (m_bLogVerbose) WriteLog(_("Connection accepted.")); } else WriteLog(_("Connection REFUSED!")); } break; default: WriteLog(_("Unhandled server event!")); break; } } struct TCommand : public wxObject { wxSocketBase* m_Sock; wxString m_Command; }; void TBaseServerApp::OnSocketEvent(wxSocketEvent& e) { wxSocketBase* sock = e.GetSocket(); switch(e.GetSocketEvent()) { case wxSOCKET_INPUT: if (sock != NULL && sock->IsOk()) { // We disable input events, so that the test doesn't trigger wxSocketEvent again. sock->SetNotify(wxSOCKET_LOST_FLAG); TCommand* message = new TCommand; message->m_Sock = sock; // Read the data const size_t BUFSIZE = 1024; wxChar buf[BUFSIZE + 16]; memset(buf, 0, sizeof(buf)); while (sock->Read(buf, BUFSIZE).LastCount() == BUFSIZE) { message->m_Command << buf; memset(buf, 0, sizeof(buf)); } message->m_Command << buf; m_Sockets.Add(message); // Enable input events again. sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG); } break; case wxSOCKET_LOST: if (m_bLogVerbose) WriteLog("--- Socket lost."); if (sock != NULL) { for (int i = m_Sockets.GetCount()-1; i >= 0; i--) { TCommand& cmd = *(TCommand*)m_Sockets[i]; if (cmd.m_Sock == sock) m_Sockets.RemoveAt(i); } if (sock->IsOk()) sock->Destroy(); } break; default: break; } } void TBaseServerApp::OnDatagramEvent(wxSocketEvent& WXUNUSED(e)) { } void TBaseServerApp::OnIdle(wxIdleEvent& evt) { if (m_Sockets.GetCount() > 0) { TCommand& cmd = *(TCommand*)m_Sockets[0]; wxSocketBase& sock = *cmd.m_Sock; const bool valid_socket = sock.IsOk(); if (valid_socket) sock.SetNotify(wxSOCKET_LOST_FLAG); wxString& str = cmd.m_Command; //scrive sul log solo se chiacchierone! if (m_bLogVerbose) WriteLog(str); if (CanProcessCommand(str, sock)) { const wxSocketFlags flags = sock.GetFlags(); if (valid_socket) sock.SetFlags(wxSOCKET_WAITALL); ProcessCommand(str, sock); if (valid_socket) sock.SetFlags(flags); } // Enable input events again. if (valid_socket) { sock.SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG); sock.Notify(true); } m_Sockets.RemoveAt(0); evt.RequestMore(); // FONDAMENTALE per gestire richieste multiple! } wxApp::OnIdle(evt); } const wxString& TBaseServerApp::GetConfigName() const { if (m_strIni.IsEmpty()) { wxFileName name(argv[0]); // Prendo il persorso completo del server in esecuzione name.SetName("servers"); // Trasformo il nome in servers ... name.SetExt("ini"); // ... e l'esetensione in .ini name.MakeAbsolute(); (wxString&)m_strIni = name.GetFullPath(); } return m_strIni; } wxString TBaseServerApp::GetConfigFileString(const wxChar* file, const wxChar* paragraph, const wxChar* key, const wxChar* def) const { wxString str; if (file == NULL || *file <= ' ') file = GetConfigName(); if (paragraph == NULL || *paragraph <= ' ') paragraph = GetAppName(); #ifdef __WXMSW__ wxChar value[512]; memset(value, 0, sizeof(value)); const int len = ::GetPrivateProfileString(paragraph, key, def, value, sizeof(value)-1, file); str = len <= 0 ? def : value; #else wxFileConfig ini("", "", file, "", wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_RELATIVE_PATH); str << '/' << paragraph; ini.SetPath(str); ini.Read(key, &str, def); #endif return str; } long TBaseServerApp::GetConfigFileInt(const wxChar* file, const wxChar* paragraph, const wxChar* key, long val) const { const wxString str = GetConfigFileString(file, paragraph, key, "*"); if (str != "*") str.ToLong(&val); return val; } void TBaseServerApp::SetConfigFileString(const wxChar* file, const wxChar* paragraph, const wxChar* key, const wxChar* val) const { if (file == NULL || *file <= ' ') file = GetConfigName(); if (paragraph == NULL || *paragraph <= ' ') paragraph = GetAppName(); #ifdef __WXMSW__ ::WritePrivateProfileString(paragraph, key, val, file); #else wxFileConfig ini("", "", file, "", wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_RELATIVE_PATH); wxString str; str << '/' << paragraph; ini.SetPath(str); ini.Write(key, val); #endif } void TBaseServerApp::SetConfigString(const wxChar* key, const wxChar* val, const wxChar* app) const { return SetConfigFileString(NULL, app, key, val); } void TBaseServerApp::SetConfigInt(const wxChar* key, int val, const wxChar* app) const { wxString str; str.Printf("%d", val); SetConfigString(key, str, app); } wxString TBaseServerApp::GetConfigString(const wxChar* key, const wxChar* def, const wxChar* app) const { return GetConfigFileString(NULL, app, key, def); } int TBaseServerApp::GetConfigInt(const wxChar* key, int def, const wxChar* app) const { return GetConfigFileInt(NULL, app, key, def); } bool TBaseServerApp::GetConfigBool(const wxChar* key, bool def, const wxChar* app) const { bool val = def; const wxString str = GetConfigString(key, "*", app); if (str != "*") val = (str[0u] == '1') || (str[0u] == 'T') || (str[0u] == 'X') || (str[0u] == 'Y') || (str.CmpNoCase("On") == 0); return val; } int TBaseServerApp::GetDefaultPort() const { return GetConfigInt("Port", 3883); } int TBaseServerApp::GetUDPPort() const { return GetConfigInt("PortUDP", 0); } #define OEM_INI wxT("../setup/oem.ini") int TBaseServerApp::GetOemInt(const wxChar* key, int def) const { static int _oem = GetConfigFileInt(OEM_INI, "MAIN", "OEM", -1); if (_oem >= 0) { if (wxStrcmp(key, wxT("OEM")) != 0) { wxString str; str.Printf(wxT("OEM_%d"), _oem); def = GetConfigFileInt(OEM_INI, str, key, def); } else def = _oem; } return def; } wxString TBaseServerApp::GetOemString(const wxChar* key, const wxChar* def) const { const int oem = GetOemInt("OEM", -1); wxString str = def; if (oem >= 0) { if (wxStrcmp(key, "OEM") != 0) { str.Printf("OEM_%d", oem); str = GetConfigFileString(OEM_INI, str, key, def); } else str.Printf("%d", oem); } return str; } wxString TBaseServerApp::GetInstallString(const wxChar* key, const wxChar* module) const { if (module == NULL || *module <= ' ') module = wxT("sr"); return GetConfigFileString(wxT("../install.ini"), module, key, wxEmptyString); } bool TBaseServerApp::IsAdvanced() const { const int nOEM = GetOemInt(wxT("OEM"), -1); return nOEM==0; } wxString TBaseServerApp::GetLogFileName() const { return GetConfigString("LogFile"); } wxString TBaseServerApp::GetDocumentRoot() const { return GetConfigString("DocumentRoot", m_strPath); } bool TBaseServerApp::IsRunning() const { return m_bRunning && IsMainLoopRunning() && Ok(); } bool TBaseServerApp::OnInit() { m_server = NULL; m_datagram = NULL; m_log = NULL; m_bRunning = false; m_SingleInstance = new wxSingleInstanceChecker(GetAppName()); if (m_SingleInstance->IsAnotherRunning()) { wxMessageBox(_("Another instance is already running"), GetAppName(), wxICON_HAND); delete m_SingleInstance; m_SingleInstance = NULL; return false; } wxFileName::SplitPath(argv[0], &m_strPath, NULL, NULL); if (!m_strPath.IsEmpty()) { wxSetWorkingDirectory(m_strPath); if (!wxEndsWithPathSeparator(m_strPath)) m_strPath += wxFILE_SEP_PATH; } // Create the address - defaults to localhost:0 initially wxIPV4address addr; addr.AnyAddress(); // I docs affermano che AnyAddress sia meglio di LocalHost const int nTCPPort = GetDefaultPort(); addr.Service(nTCPPort); // Create the TCP socket m_server = new wxSocketServer(addr); // Create the Log file //Prima di creare il nuovo log file (vuoto) salva quello vecchio aggiungendo al nome data e ora di ripartenza.. //..Serve per monitorare i defungimenti dei server const wxString strLog = GetLogFileName(); if (!strLog.IsEmpty()) { wxFileName fnLogFileName(strLog); if (fnLogFileName.FileExists()) { const wxDateTime dtNow = wxDateTime::Now(); wxString strWorkString; strWorkString.Printf("%04d%02d%02d_%02d%02d_", dtNow.GetYear(), dtNow.GetMonth() + 1, dtNow.GetDay(), dtNow.GetHour(), dtNow.GetMinute()); strWorkString << fnLogFileName.GetName(); fnLogFileName.SetName(strWorkString); wxCopyFile(strLog, fnLogFileName.GetFullPath()); } m_log = new wxFileOutputStream(strLog); m_bLogVerbose = GetConfigBool("LogVerbose"); } else { m_log = NULL; m_bLogVerbose = false; } m_nTmpCounter = 0; // We use Ok() here to see if the server is really listening if (m_server->Ok()) { // Setup the event handler and subscribe to connection events m_server->SetEventHandler(*this, SERVER_ID); m_server->SetNotify(wxSOCKET_CONNECTION_FLAG); m_server->Notify(true); wxString str; str << GetAppName() << _(" listening at ") << addr.Hostname() << wxT(":") << addr.Service(); WriteLog(str); m_bRunning = Initialization(); } else { wxString str; str << GetAppName() << _(" could not listen to port ") << addr.Service(); WriteLog(str); } #ifdef wxHAS_TASK_BAR_ICON m_Tray = NULL; if (m_bRunning) { m_Tray = new TTaskBarIcon; m_Tray->Init(); } #endif /* // Create the UDP socket const int nUDPPort = GetUDPPort(); if (m_bRunning && nUDPPort > nTCPPort) { wxIPV4address udp_addr; udp_addr.AnyAddress(); // I docs affermano che AnyAddress sia meglio di LocalHost udp_addr.Service(nUDPPort); m_datagram = new wxDatagramSocket(udp_addr); // Setup the event handler and subscribe to connection events m_datagram->SetEventHandler(*this, DATAGRAM_ID); m_datagram->Notify(true); } */ return m_bRunning; } int TBaseServerApp::OnExit() { if (m_server != NULL) { m_bRunning = false; Deinitialization(); delete m_SingleInstance; m_SingleInstance = NULL; delete m_server; m_server = NULL; } if (m_log != NULL) { wxString str; str << GetAppName() << " shutting down."; WriteLog(str); delete m_log; m_log = NULL; } #ifdef wxHAS_TASK_BAR_ICON if (m_Tray != NULL) { m_Tray->RemoveIcon(); delete m_Tray; m_Tray = NULL; } #endif return wxApp::OnExit(); } wxString TBaseServerApp::UnformatString(const wxString& strFormString) const { wxString strResult; for (int i = 0; strFormString[i]; i++) { switch(strFormString[i]) { case '+': strResult += ' '; break; case '%': { const wxChar c = hex2int(strFormString.Mid(i+1, 2)); strResult += c; i += 2; } break; default: strResult += strFormString[i]; break; } } return strResult; } size_t TBaseServerApp::ParseArguments(wxString args, THashTable& hashArgs) const { int uguale = args.Find('='); while (uguale > 0) { wxString name = args.Left(uguale); name.Trim(false); name.Trim(true); wxString value; const int acapo = args.Find('&'); if (acapo > uguale) value = args.Mid(uguale+1, acapo-uguale-1); else value = args.Mid(uguale+1); value.Trim(false); value.Trim(true); hashArgs.Put(name, UnformatString(value)); if (acapo > 0) { args = args.Mid(acapo+1); uguale = args.Find('='); } else uguale = -1; } return hashArgs.GetCount(); } bool TBaseServerApp::GetVersionInfo(int& year, int& release, int& tag, int& patch) const { const char* const VERSIONANDPATCH = "Don't cry for me Argentina.2091.10.00.0000.2101"; wxStringTokenizer tok(VERSIONANDPATCH, wxT(".")); tok.GetNextToken(); // Ignore string year = wxAtoi(tok.GetNextToken()); release = wxAtoi(tok.GetNextToken()); tag = wxAtoi(tok.GetNextToken()); patch = wxAtoi(tok.GetNextToken()); int checksum = wxAtoi(tok.GetNextToken()); bool valid = year >= 2091 && release > 0 && tag >= 0 && patch >= 0 && checksum == (year + release + tag + patch); return valid; }