///////////////////////////////////////////////////////////////////////////// // Name: server.cpp // Purpose: Simple Soap Server // Author: Guy // Modified by: // Created: 21/08/2002 // Copyright: (c) 2002 Guy // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ========================================================================== // declarations // ========================================================================== // -------------------------------------------------------------------------- // headers // -------------------------------------------------------------------------- #include #include #include #include #include "soap.h" // -------------------------------------------------------------------------- // classes // -------------------------------------------------------------------------- // Define a new application type class SoapServerApp : public wxApp { public: virtual bool OnInit(); }; // Define a new frame type: this is going to be our main frame class SoapFrame : public wxFrame { clock_t m_last_text; public: SoapFrame(); ~SoapFrame(); // event handlers (these functions should _not_ be virtual) void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); void OnServerEvent(wxSocketEvent& event); void OnSocketEvent(wxSocketEvent& event); // Roba mia void AppendText(const wxChar* str); int GetDefaultPort() const; void ProcessSoapCommand(wxSocketBase *sock); // convenience functions void UpdateStatusBar(); private: wxSocketServer *m_server; wxTextCtrl *m_text; wxMenu *m_menuFile; wxMenuBar *m_menuBar; bool m_busy; int m_numClients; // any class wishing to process wxWindows events must use this macro DECLARE_EVENT_TABLE() }; // -------------------------------------------------------------------------- // constants // -------------------------------------------------------------------------- // IDs for the controls and the menu commands enum { // menu items SERVER_QUIT = 1000, SERVER_ABOUT, // id for sockets SERVER_ID, SOCKET_ID }; // -------------------------------------------------------------------------- // event tables and other macros for wxWindows // -------------------------------------------------------------------------- BEGIN_EVENT_TABLE(SoapFrame, wxFrame) EVT_MENU(SERVER_QUIT, SoapFrame::OnQuit) EVT_MENU(SERVER_ABOUT, SoapFrame::OnAbout) EVT_SOCKET(SERVER_ID, SoapFrame::OnServerEvent) EVT_SOCKET(SOCKET_ID, SoapFrame::OnSocketEvent) END_EVENT_TABLE() IMPLEMENT_APP(SoapServerApp) // ========================================================================== // implementation // ========================================================================== // -------------------------------------------------------------------------- // the application class // -------------------------------------------------------------------------- bool SoapServerApp::OnInit() { // Create the main application window SoapFrame *frame = new SoapFrame(); // Show it and tell the application that it's our main window frame->Show(TRUE); SetTopWindow(frame); // Success return TRUE; } // -------------------------------------------------------------------------- // main frame // -------------------------------------------------------------------------- int SoapFrame::GetDefaultPort() const { int nPort = 3883; wxIniConfig ini("", "", "./campo.ini"); ini.SetPath("/Server"); const wxString str = ini.Read("Dictionary", ""); const int colon = str.Find(':'); if (colon > 0) nPort = atoi(str.Mid(colon+1)); return nPort; } void SoapFrame::AppendText(const wxChar* str) { const clock_t now = clock(); if (now - m_last_text > 60000) m_text->SetValue(str); else m_text->AppendText(str); m_last_text = now; } // frame constructor SoapFrame::SoapFrame() : wxFrame((wxFrame *)NULL, -1, "Soap Server", wxDefaultPosition, wxSize(300, 300)) { // Give the frame an icon SetIcon(wxICON(mondrian)); // Make menus m_menuFile = new wxMenu(); m_menuFile->Append(SERVER_ABOUT, "&About...\tCtrl-A", "Show about dialog"); m_menuFile->AppendSeparator(); m_menuFile->Append(SERVER_QUIT, "E&xit\tAlt-X", "Quit server"); // Append menus to the menubar m_menuBar = new wxMenuBar(); m_menuBar->Append(m_menuFile, "&File"); SetMenuBar(m_menuBar); // Make a textctrl for logging m_text = new wxTextCtrl(this, -1, "Welcome to SOAP Server\n", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY); // Status bar CreateStatusBar(2); // Create the address - defaults to localhost:0 initially wxIPV4address addr; addr.Service(GetDefaultPort()); // Create the socket m_server = new wxSocketServer(addr); m_last_text = clock(); // We use Ok() here to see if the server is really listening if (! m_server->Ok()) { wxString str; str << "Could not listen to port " << addr.Service() << "\n\n"; AppendText(str); return; } else { wxString str; str << "Server listening on port " << addr.Service() << "\n\n"; AppendText(str); } // 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); m_busy = FALSE; m_numClients = 0; UpdateStatusBar(); } SoapFrame::~SoapFrame() { // No delayed deletion here, as the frame is dying anyway delete m_server; } // event handlers void SoapFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) { // TRUE is to force the frame to close Close(TRUE); } void SoapFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { wxMessageBox("Soap Server\n(c) 2002 by Aga\n", "About Soap Server", wxOK | wxICON_INFORMATION, this); } void SoapFrame::ProcessSoapCommand(wxSocketBase *sock) { sock->SetFlags(wxSOCKET_NOWAIT); // Read the data wxChar buf[4096]; memset(buf, 0, sizeof(buf)); unsigned int len = sock->Read(buf, sizeof(buf)).LastCount(); AppendText(buf); wxString strAnswer = SoapProcessMessage(buf, len); AppendText("\n\n"); AppendText(strAnswer); // Write it back sock->Write(strAnswer, strAnswer.Length()); } void SoapFrame::OnServerEvent(wxSocketEvent& event) { wxString s = "OnServerEvent: "; wxSocketBase *sock; switch(event.GetSocketEvent()) { case wxSOCKET_CONNECTION : s.Append("wxSOCKET_CONNECTION\n"); break; default : s.Append("Unexpected event !\n"); break; } AppendText(s); // 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). sock = m_server->Accept(FALSE); if (sock) { AppendText("New client connection accepted\n\n"); } else { AppendText("Error: couldn't accept a new connection\n\n"); sock->Destroy(); return; } sock->SetEventHandler(*this, SOCKET_ID); sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); sock->Notify(TRUE); m_numClients++; UpdateStatusBar(); } void SoapFrame::OnSocketEvent(wxSocketEvent& event) { wxString s = "OnSocketEvent: "; wxSocketBase *sock = event.GetSocket(); // First, print a message switch(event.GetSocketEvent()) { case wxSOCKET_INPUT : s.Append("wxSOCKET_INPUT\n"); break; case wxSOCKET_LOST : s.Append("wxSOCKET_LOST\n"); break; default : s.Append("Unexpected event !\n"); break; } AppendText(s); // Now we process the event switch(event.GetSocketEvent()) { case wxSOCKET_INPUT: { // We disable input events, so that the test doesn't trigger // wxSocketEvent again. sock->SetNotify(wxSOCKET_LOST_FLAG); ProcessSoapCommand(sock); // Enable input events again. sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG); break; } case wxSOCKET_LOST: { m_numClients--; // Destroy() should be used instead of delete wherever possible, // due to the fact that wxSocket uses 'delayed events' (see the // documentation for wxPostEvent) and we don't want an event to // arrive to the event handler (the frame, here) after the socket // has been deleted. Also, we might be doing some other thing with // the socket at the same time; for example, we might be in the // middle of a test or something. Destroy() takes care of all // this for us. AppendText("Deleting socket.\n\n"); sock->Destroy(); break; } default: ; } UpdateStatusBar(); } // convenience functions void SoapFrame::UpdateStatusBar() { wxString s; s.Printf("%d clients connected", m_numClients); SetStatusText(s, 1); }