]> git.saurik.com Git - wxWidgets.git/blobdiff - samples/wxsocket/server.cpp
tests for "big" wxTextCtrls
[wxWidgets.git] / samples / wxsocket / server.cpp
index 3d6438fe2903703096d855dd1d28e967646cc1c9..817c15657b65774b063f28287970dbb5f2f5a964 100644 (file)
-/*
- * File:       server.cpp
- * Purpose:    wxSocket: server demo
- * Author:     LAVAUX Guilhem
- * Created:    June 1997
- * CVS Id:     $Id$
- * Copyright: (C) 1997, LAVAUX Guilhem
- */
+/////////////////////////////////////////////////////////////////////////////
+// Name:        server.cpp
+// Purpose:     Server for wxSocket demo
+// Author:      Guillermo Rodriguez Garcia <guille@iies.es>
+// Modified by:
+// Created:     1999/09/19
+// RCS-ID:      $Id$
+// Copyright:   (c) 1999 Guillermo Rodriguez Garcia
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ==========================================================================
+// declarations
+// ==========================================================================
+
+// --------------------------------------------------------------------------
+// headers
+// --------------------------------------------------------------------------
 
 #ifdef __GNUG__
-#pragma implementation
-#pragma interface
+#  pragma implementation "server.cpp"
+#  pragma interface "server.cpp"
 #endif
 
-// For compilers that support precompilation, includes "wx.h".
+// For compilers that support precompilation, includes "wx/wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-#pragma hdrstop
+#  pragma hdrstop
 #endif
 
+// for all others, include the necessary headers 
 #ifndef WX_PRECOMP
-#include "wx/wx.h"
+#  include "wx/wx.h"
 #endif
 
 #include "wx/socket.h"
-#include "wx/thread.h"
 
-#if defined(__WXMOTIF__) || defined(__WXGTK__)
-#include "mondrian.xpm"
+// --------------------------------------------------------------------------
+// resources
+// --------------------------------------------------------------------------
+
+// the application icon
+#if defined(__WXGTK__) || defined(__WXMOTIF__)
+#  include "mondrian.xpm"
 #endif
 
+// --------------------------------------------------------------------------
+// classes
+// --------------------------------------------------------------------------
+
 // Define a new application type
-class MyApp: public wxApp
-{ public:
-    bool OnInit(void);
+class MyApp : public wxApp
+{
+public:
+  virtual bool OnInit();
 };
 
-class MyServer;
-
-// Define a new frame type
-class MyFrame: public wxFrame
-{ 
-  DECLARE_EVENT_TABLE()
+// Define a new frame type: this is going to be our main frame
+class MyFrame : public wxFrame
+{
 public:
-  wxSocketServer *sock;
-  int nb_clients;
-
-  MyFrame(wxFrame *frame);
-  virtual ~MyFrame();
-  void Menu_Exit(wxCommandEvent& evt);
-  void OnSockRequest(wxSocketEvent& evt);
-  void OnSockRequestServer(wxSocketEvent& evt);
-  void ExecTest1(wxSocketBase *sock_o);
-  void UpdateStatus(int incr);
+  MyFrame();
+  ~MyFrame();
+
+  // event handlers (these functions should _not_ be virtual)
+  void OnQuit(wxCommandEvent& event);
+  void OnAbout(wxCommandEvent& event);
+  void OnServerEvent(wxSocketEvent& event);
+  void OnSocketEvent(wxSocketEvent& event);
+
+  void Test1(wxSocketBase *sock);
+  void Test2(wxSocketBase *sock);
+  void Test3(wxSocketBase *sock);
+
+  // convenience functions
+  void UpdateStatusBar();
+
+private:
+  wxSocketServer *m_server;
+  wxPanel        *m_panel;
+  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()
 };
 
-#define SKDEMO_QUIT 101
-#define SKDEMO_SOCKET_SERV 102
-#define SKDEMO_SOCKET 103
+// --------------------------------------------------------------------------
+// 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(MyFrame, wxFrame)
-  EVT_MENU(SKDEMO_QUIT, MyFrame::Menu_Exit)
-  EVT_SOCKET(SKDEMO_SOCKET_SERV, MyFrame::OnSockRequestServer)
-  EVT_SOCKET(SKDEMO_SOCKET, MyFrame::OnSockRequest)
+  EVT_MENU(SERVER_QUIT,  MyFrame::OnQuit)
+  EVT_MENU(SERVER_ABOUT, MyFrame::OnAbout)
+  EVT_SOCKET(SERVER_ID,  MyFrame::OnServerEvent)
+  EVT_SOCKET(SOCKET_ID,  MyFrame::OnSocketEvent)
 END_EVENT_TABLE()
 
 IMPLEMENT_APP(MyApp)
 
-// `Main program' equivalent, creating windows and returning main app frame
-bool MyApp::OnInit(void)
-{
-  // Create the main frame window
-  MyFrame *frame = new MyFrame(NULL);
 
-  // Give it an icon
-  frame->SetIcon(wxICON(mondrian));
+// To append sockets for delayed deletion
+extern wxList wxPendingDelete;
+
 
-  // Make a menubar
-  wxMenu *file_menu = new wxMenu;
+// ==========================================================================
+// implementation
+// ==========================================================================
 
-  file_menu->Append(SKDEMO_QUIT, "E&xit");
-  wxMenuBar *menu_bar = new wxMenuBar;
-  menu_bar->Append(file_menu, "File");
-  frame->SetMenuBar(menu_bar);
+// --------------------------------------------------------------------------
+// the application class
+// --------------------------------------------------------------------------
 
-  // Make a panel with a message
-  (void)new wxPanel(frame, 0, 0, 300, 100);
+bool MyApp::OnInit()
+{
+  // Create the main application window
+  MyFrame *frame = new MyFrame();
 
-  // Show the frame
+  // Show it and tell the application that it's our main window
   frame->Show(TRUE);
-  
-  // Return the main frame window
+  SetTopWindow(frame);
+
+  // success
   return TRUE;
 }
 
-extern wxList wxPendingDelete;
+// --------------------------------------------------------------------------
+// main frame
+// --------------------------------------------------------------------------
 
-void MyFrame::OnSockRequest(wxSocketEvent& evt)
+// frame constructor
+MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, -1,
+                             _T("wxSocket demo: Server"),
+                             wxDefaultPosition, wxSize(300, 200))
 {
-  /* this routine gets called from within the
-     waiting socket thread, i.e. here we are
-     not in the main GUI thread and thus we
-     must not call any GUI function here. */
-  /* Wrong ! This routine is called by the main GUI thread
-     because the main GUI thread received a signal from the other
-     thread using wxEvent::ProcessThreadEvent */
-
-  wxSocketBase *sock = evt.Socket();
-
-  wxPrintf(_T("OnSockRequest OK\n"));
-  wxPrintf(_T("OnSockRequest (event = %d)\n"),evt.SocketEvent());
-  switch (evt.SocketEvent()) {
-  case wxSOCKET_INPUT:
-    unsigned char c;
-
-    sock->Read((char *)&c, 1);
-    if (c == 0xbe)
-      ExecTest1(sock);
-
-    break;
-  case wxSOCKET_LOST:
-    wxPrintf(_T("Destroying socket\n"));
-    wxPendingDelete.Append(sock);
-    UpdateStatus(-1);
-    return;
-    break;
-  default:
-    wxPrintf(_T("Invalid event !\n"));
-  }
-  wxPrintf(_T("OnSockRequest Exiting\n"));
+  // Give the frame an icon
+  SetIcon(wxICON(mondrian));
+
+  // Make menus
+  m_menuFile = new wxMenu();
+  m_menuFile->Append(SERVER_ABOUT, _T("&About...\tCtrl-A"), _T("Show about dialog"));
+  m_menuFile->AppendSeparator();
+  m_menuFile->Append(SERVER_QUIT, _T("E&xit\tAlt-X"), _T("Quit server"));
+
+  // Append menus to the menubar
+  m_menuBar = new wxMenuBar();
+  m_menuBar->Append(m_menuFile, _T("&File"));
+  SetMenuBar(m_menuBar);
+
+  // Status bar
+  CreateStatusBar(2);
+
+  // Make a panel with a textctrl in it
+  m_panel = new wxPanel(this, -1, wxPoint(0, 0), GetClientSize());
+  m_text  = new wxTextCtrl(m_panel, -1,
+                           _T("Welcome to wxSocket demo: Server\n"),
+                           wxPoint(0, 0), m_panel->GetClientSize(),
+                           wxTE_MULTILINE | wxTE_READONLY);
+
+  // Create the socket
+  wxIPV4address addr;
+  addr.Service(3000);
+  addr.LocalHost();
+
+  m_server = new wxSocketServer(addr);
+  m_server->SetEventHandler(*this, SERVER_ID);
+  m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
+  m_server->Notify(TRUE);
+
+  // We use Ok() here to see if the server is really listening
+  if (m_server->Ok())
+    m_text->AppendText(_T("Server listening.\n\n"));
+  else
+    m_text->AppendText(_T("Could not listen at the specified port !\n\n"));
+
+  m_busy = FALSE;
+  m_numClients = 0;
+  UpdateStatusBar();
 }
 
-void MyFrame::OnSockRequestServer(wxSocketEvent& evt)
+MyFrame::~MyFrame()
 {
-  /* this routine gets called from within the
-     waiting socket thread, i.e. here we are
-     not in the main GUI thread and thus we
-     must not call any GUI function here. */
-  /* Wrong ! This routine is called by the main GUI thread
-     because the main GUI thread received a signal from the other
-     thread using wxEvent::ProcessThreadEvent */
-
-  wxSocketBase *sock2;
-  wxSocketServer *server = (wxSocketServer *) evt.Socket();
-
-  wxPrintf(_T("OnSockRequestServer OK\n"));
-  wxPrintf(_T("OnSockRequest (Main = %d) (event = %d)\n"),wxThread::IsMain(), evt.SocketEvent());
-
-  sock2 = server->Accept();
-  if (sock2 == NULL)
-    return;
+  delete m_server;
+}
 
-  UpdateStatus(1);
-  sock2->SetFlags(wxSocketBase::NONE);
-  sock2->Notify(TRUE);
-  sock2->SetEventHandler(*this, SKDEMO_SOCKET);
-  sock2->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
+// event handlers
+
+void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
+{
+  // TRUE is to force the frame to close
+  Close(TRUE);
 }
 
-// My frame Constructor
-MyFrame::MyFrame(wxFrame *frame):
-  wxFrame(frame, -1, "wxSocket sample (server)", wxDefaultPosition,
-          wxSize(300, 200))
+void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
 {
-  wxIPV4address addr;
-  addr.Service(3000);
+  wxMessageBox(_T("wxSocket demo: Server\n")
+               _T("(c) 1999 Guillermo Rodriguez Garcia\n"),
+               _T("About Server"),
+               wxOK | wxICON_INFORMATION, this);
+}
 
-  // Init all
+void MyFrame::Test1(wxSocketBase *sock)
+{
+  unsigned char len;
+  char *buf;
 
-  sock = new wxSocketServer(addr);
-  sock->SetNotify(wxSOCKET_CONNECTION_FLAG);
-  sock->SetEventHandler(*this, SKDEMO_SOCKET_SERV);
-  sock->SetFlags(wxSocketBase::SPEED);
-  sock->Notify(TRUE);
-  nb_clients = 0;
+  m_text->AppendText(_T("Test 1 begins\n"));
+
+  // Receive data from socket and send it back. We will first
+  // get a byte with the buffer size, so we can specify the
+  // exact size and use the WAITALL flag. Also, we disabled
+  // input events so we won't have unwanted reentrance. This
+  // way we can avoid the infamous BLOCK (formerly SPEED) flag.
+  //
+  sock->SetFlags(wxSOCKET_WAITALL);
+
+  sock->Read((char *)&len, 1);
 
-  CreateStatusBar(1);
-  UpdateStatus(0);
+  buf = (char *)malloc(len);
+  sock->Read(buf, len);
+  sock->Write(buf, len);
+  free(buf);
+
+  m_text->AppendText(_T("Test 1 ends\n"));
 }
 
-MyFrame::~MyFrame()
+void MyFrame::Test2(wxSocketBase *sock)
 {
-  delete sock;
+#define MAX_MSG_SIZE 10000
+
+  wxString s;
+  char *buf = (char *)malloc(MAX_MSG_SIZE);
+  wxUint32 len;
+
+  m_text->AppendText(_T("Test 2 begins\n"));
+
+  // We don't need to set flags because ReadMsg and WriteMsg
+  // are not affected by them anyway.
+  //
+  len = sock->ReadMsg(buf, MAX_MSG_SIZE).LastCount();
+
+  s.Printf(_T("Client says: %s\n"), buf);
+  m_text->AppendText(s);
+
+  sock->WriteMsg(buf, len);
+  free(buf);
+
+  m_text->AppendText(_T("Test 2 ends\n"));
+
+#undef MAX_MSG_SIZE
 }
 
-// Intercept menu commands
-void MyFrame::Menu_Exit(wxCommandEvent& WXUNUSED(event))
+void MyFrame::Test3(wxSocketBase *sock)
 {
-  Close(TRUE);
+  m_text->AppendText(_T("Test 3 begins\n"));
+  m_text->AppendText(_T("(not implemented)\n"));
+  m_text->AppendText(_T("Test 3 ends\n"));
 }
 
-void MyFrame::ExecTest1(wxSocketBase *sock_o)
+void MyFrame::OnServerEvent(wxSocketEvent& event)
 {
-  char *buf = new char[50];
-  size_t l;
+  wxString s = _T("OnServerEvent: ");
+  wxSocketBase *sock;
+
+  switch(event.SocketEvent())
+  {
+    case wxSOCKET_CONNECTION : s.Append(_T("wxSOCKET_CONNECTION\n")); break;
+    default                  : s.Append(_T("Unexpected event !\n")); break;
+  }
 
-  l = sock_o->Read(buf, 50).LastCount();
-  sock_o->Write(buf, l);
-  l = sock_o->Read(buf, 50).LastCount();
-  sock_o->Write(buf, l);
+  m_text->AppendText(s);
 
-  delete[] buf;
+  // 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)
+  {
+    m_text->AppendText(_T("New client connection accepted\n"));
+  }
+  else
+  {
+    m_text->AppendText(_T("Error: couldn't accept a new connection"));
+    return;
+  }
+
+  sock->SetEventHandler(*this, SOCKET_ID);
+  sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
+  sock->Notify(TRUE);
+
+  m_numClients++;
+  UpdateStatusBar();
 }
 
-void MyFrame::UpdateStatus(int incr)
+void MyFrame::OnSocketEvent(wxSocketEvent& event)
+{
+  wxSocketBase *sock = event.Socket();
+  wxString s = _T("OnSocketEvent: ");
+
+  // We first print a msg
+  switch(event.SocketEvent())
+  {
+    case wxSOCKET_INPUT: s.Append(_T("wxSOCKET_INPUT\n")); break;
+    case wxSOCKET_LOST:  s.Append(_T("wxSOCKET_LOST\n")); break;
+    default:             s.Append(_T("unexpected event !\n"));
+  }
+
+  m_text->AppendText(s);
+
+  // Now we process the event
+  switch(event.SocketEvent())
+  {
+    case wxSOCKET_INPUT:
+    {
+      // We disable input events, so that the test doesn't trigger
+      // wxSocketEvent again.
+      sock->SetNotify(wxSOCKET_LOST_FLAG);
+
+      // Which test are we going to run?
+      unsigned char c;
+      sock->Read((char *)&c ,1);
+
+      switch (c)
+      {
+        case 0xBE: Test1(sock); break;
+        case 0xCE: Test2(sock); break;
+        case 0xDE: Test3(sock); break;
+        default: s.Append(_T("Unknown test id received from client\n"));
+      }
+
+      // Enable input events again.
+      sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG);
+      break;
+    }
+    case wxSOCKET_LOST:
+    {
+      m_numClients--;
+
+      // We cannot delete the socket right now because we can
+      // be in the middle of a test or something. So we append
+      // it to the list of objects to be deleted.
+      m_text->AppendText(_T("Deleting socket.\n"));
+      wxPendingDelete.Append(sock);
+      break;
+    }
+    default: ;
+  }
+
+  UpdateStatusBar();
+}
+
+// convenience functions
+
+void MyFrame::UpdateStatusBar()
 {
-  wxChar s[30];
-  nb_clients += incr;
-  wxSprintf(s, _T("%d clients connected"), nb_clients);
-  SetStatusText(s);
+  wxString s;
+  s.Printf(_T("%d clients connected"), m_numClients);
+  SetStatusText(s, 1);
 }