Please help with memory leak !!!

Petr Chládek pchladek at retia.cz
Fri Aug 24 03:59:17 PDT 2007


Hi,

I'm using wxGTK-2.8.4 (Suse 9.3) and I probably noticed a memory leak. I saw increasing TCP server memory need with htop (column RES) during receiving data (top is insufficient because of it shows RES in MBytes). I adjusted examples/sockets/client.cpp and server.cpp for better demonstration (see below). TCP client is sending data (very fast - with 32 ms interval) and TCP server is receiving it without any logging.

When I'm using wxGTK-2.6.3 or wxMSW-2.8.4 there's no problem.
Thanks
Petr Chladek

Using example: Connect a client to server and run Test1. After 1 minute
 you'll see growing memory allocation for server.


---------------------------- server.cpp -------------------------------------

/////////////////////////////////////////////////////////////////////////////
// Name:        server.cpp
// Purpose:     Server for wxSocket demo
// Author:      Guillermo Rodriguez Garcia <guille at iies.es>
// Modified by:
// Created:     1999/09/19
// RCS-ID:      $Id: server.cpp,v 1.21 2005/09/23 12:52:25 MR Exp $
// Copyright:   (c) 1999 Guillermo Rodriguez Garcia
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ==========================================================================
// declarations
// ==========================================================================

// --------------------------------------------------------------------------
// headers
// --------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef   BORLANDC  
#  pragma hdrstop
#endif

// for all others, include the necessary headers
#ifndef WX PRECOMP
#  include "wx/wx.h"
#endif

#include "wx/socket.h"

// --------------------------------------------------------------------------
// resources
// --------------------------------------------------------------------------

// the application icon
#if defined(  WXGTK  ) || defined(  WXX11  ) || defined(  WXMOTIF  ) || 
defined(  WXMAC  )
#  include "mondrian.xpm"
#endif

// --------------------------------------------------------------------------
// classes
// --------------------------------------------------------------------------

// Define a new application type
class MyApp : public wxApp
{
public:
  virtual bool OnInit();
};

// Define a new frame type: this is going to be our main frame
class MyFrame : public wxFrame
{
public:
  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;
  wxTextCtrl     *m text;
  wxMenu         *m menuFile;
  wxMenuBar      *m menuBar;
  bool            m busy;
  int             m numClients;

  // any class wishing to process wxWidgets events must use this macro
  DECLARE EVENT TABLE()
};

// --------------------------------------------------------------------------
// constants
// --------------------------------------------------------------------------

// IDs for the controls and the menu commands
enum
{
  // menu items
  SERVER QUIT = wxID EXIT,
  SERVER ABOUT = wxID ABOUT,

  // id for sockets
  SERVER ID = 100,
  SOCKET ID
};

// --------------------------------------------------------------------------
// event tables and other macros for wxWidgets
// --------------------------------------------------------------------------

BEGIN EVENT TABLE(MyFrame, wxFrame)
  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)


// ==========================================================================
// implementation
// ==========================================================================

// --------------------------------------------------------------------------
// the application class
// --------------------------------------------------------------------------

bool MyApp::OnInit()
{
  // Create the main application window
  MyFrame *frame = new MyFrame();

  // Show it and tell the application that it's our main window
  frame->Show(true);
  SetTopWindow(frame);

  // Success
  return true;
}

// --------------------------------------------------------------------------
// main frame
// --------------------------------------------------------------------------

// frame constructor

MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, wxID ANY,
                              ("wxSocket demo: Server"),
                             wxDefaultPosition, wxSize(300, 200))
{
  // 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);

#if wxUSE STATUSBAR
  // Status bar
  CreateStatusBar(2);
#endif // wxUSE STATUSBAR

  // Make a textctrl for logging
  m text  = new wxTextCtrl(this, wxID ANY,
                            ("Welcome to wxSocket demo: Server\n"),
                           wxDefaultPosition, wxDefaultSize,
                           wxTE MULTILINE | wxTE READONLY);

  // Create the address - defaults to localhost:0 initially
  wxIPV4address addr;
  addr.Service(3000);

  // Create the socket
  m server = new wxSocketServer(addr);

  // We use Ok() here to see if the server is really listening
  if (! m server->Ok())
  {
    m text->AppendText( ("Could not listen at the specified port !\n\n"));
    return;
  }
  else
  {
    m text->AppendText( ("Server listening.\n\n"));
  }

  // 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();
}

MyFrame::~MyFrame()
{
  // No delayed deletion here, as the frame is dying anyway
  delete m server;
}

// event handlers

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
  // true is to force the frame to close
  Close(true);
}

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
  wxMessageBox( ("wxSocket demo: Server\n(c) 1999 Guillermo Rodriguez 
Garcia\n"),
                ("About Server"),
               wxOK | wxICON INFORMATION, this);
}

void MyFrame::Test1(wxSocketBase *sock)
{
  unsigned char len;
  char *buf;

  //m text->AppendText( ("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 wxSOCKET WAITALL flag. Also, we
  // disabled input events so we won't have unwanted reentrance.
  // This way we can avoid the infamous wxSOCKET BLOCK flag.

  sock->SetFlags(wxSOCKET WAITALL);

  // Read the size
  sock->Read(&len, 1);
  buf = new char[len];

  // Read the data
  sock->Read(buf, len);
  //m text->AppendText( ("Got the data, sending it back\n"));

  // Write it back
  sock->Write(buf, len);
  delete[] buf;

  //m text->AppendText( ("Test 1 ends\n\n"));
}

void MyFrame::Test2(wxSocketBase *sock)
{
#define MAX MSG SIZE 10000

  wxString s;
  wxChar *buf = new wxChar[MAX MSG SIZE];
  wxUint32 len;

  m text->AppendText( ("Test 2 begins\n"));

  // We don't need to set flags because ReadMsg and WriteMsg
  // are not affected by them anyway.

  // Read the message
  len = sock->ReadMsg(buf, MAX MSG SIZE * sizeof(wxChar)).LastCount();
  s.Printf( ("Client says: %s\n"), buf);
  m text->AppendText(s);
  m text->AppendText( ("Sending the data back\n"));

  // Write it back
  sock->WriteMsg(buf, len);
  delete[] buf;

  m text->AppendText( ("Test 2 ends\n\n"));

#undef MAX MSG SIZE
}

void MyFrame::Test3(wxSocketBase *sock)
{
  unsigned char len;
  char *buf;

  m text->AppendText( ("Test 3 begins\n"));

  // This test is similar to the first one, but the len is
  // expressed in kbytes - this tests large data transfers.

  sock->SetFlags(wxSOCKET WAITALL);

  // Read the size
  sock->Read(&len, 1);
  buf = new char[len * 1024];

  // Read the data
  sock->Read(buf, len * 1024);
  m text->AppendText( ("Got the data, sending it back\n"));

  // Write it back
  sock->Write(buf, len * 1024);
  delete[] buf;

  m text->AppendText( ("Test 3 ends\n\n"));
}

void MyFrame::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;
  }

  m text->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)
  {
    m text->AppendText( ("New client connection accepted\n\n"));
  }
  else
  {
    m text->AppendText( ("Error: couldn't accept a new connection\n\n"));
    return;
  }

  sock->SetEventHandler(*this, SOCKET ID);
  sock->SetNotify(wxSOCKET INPUT FLAG | wxSOCKET LOST FLAG);
  sock->Notify(true);

  m numClients++;
  UpdateStatusBar();
}

void MyFrame::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;
  }

  //m text->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);

      // Which test are we going to run?
      unsigned char c;
      sock->Read(&c, 1);

      switch (c)
      {
        case 0xBE: Test1(sock); break;
        case 0xCE: Test2(sock); break;
        case 0xDE: Test3(sock); break;
        default:
          m text->AppendText( ("Unknown test id received from client\n\n"));
      }

      // 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.

      m text->AppendText( ("Deleting socket.\n\n"));
      sock->Destroy();
      break;
    }
    default: ;
  }

  UpdateStatusBar();
}

// convenience functions

void MyFrame::UpdateStatusBar()
{
#if wxUSE STATUSBAR
  wxString s;
  s.Printf( ("%d clients connected"), m numClients);
  SetStatusText(s, 1);
#endif // wxUSE STATUSBAR
}



--------------------------------------- client.cpp ---------------------

/////////////////////////////////////////////////////////////////////////////
// Name:        client.cpp
// Purpose:     Client for wxSocket demo
// Author:      Guillermo Rodriguez Garcia <guille at iies.es>
// Modified by:
// Created:     1999/09/19
// RCS-ID:      $Id: client.cpp,v 1.33 2005/09/23 12:52:25 MR Exp $
// Copyright:   (c) 1999 Guillermo Rodriguez Garcia
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ==========================================================================
// declarations
// ==========================================================================

// --------------------------------------------------------------------------
// headers
// --------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef   BORLANDC  
#  pragma hdrstop
#endif

// for all others, include the necessary headers
#ifndef WX PRECOMP
#  include "wx/wx.h"
#endif

#include "wx/socket.h"
#include "wx/url.h"
#include "wx/wfstream.h"

#include "wx/utils.h"

// --------------------------------------------------------------------------
// resources
// --------------------------------------------------------------------------

// the application icon
#if defined(  WXGTK  ) || defined(  WXX11  ) || defined(  WXMOTIF  ) || 
defined(  WXMAC  )
#  include "mondrian.xpm"
#endif

// --------------------------------------------------------------------------
// classes
// --------------------------------------------------------------------------

// Define a new application type
class MyApp : public wxApp
{
public:
  virtual bool OnInit();
};

// Define a new frame type: this is going to be our main frame
class MyFrame : public wxFrame
{
public:
  MyFrame();
  ~MyFrame();

  // event handlers for File menu
  void OnQuit(wxCommandEvent& event);
  void OnAbout(wxCommandEvent& event);

  // event handlers for Socket menu
  void OnOpenConnection(wxCommandEvent& event);
  void OnTest1(wxCommandEvent& event);
  void OnTest2(wxCommandEvent& event);
  void OnTest3(wxCommandEvent& event);
  void OnCloseConnection(wxCommandEvent& event);

#if wxUSE URL
  // event handlers for Protocols menu
  void OnTestURL(wxCommandEvent& event);
#endif

  // event handlers for DatagramSocket menu (stub)
  void OnDatagram(wxCommandEvent& event);

  // socket event handler
  void OnSocketEvent(wxSocketEvent& event);

  // convenience functions
  void UpdateStatusBar();

private:
  wxSocketClient *m sock;
  wxTextCtrl     *m text;
  wxMenu         *m menuFile;
  wxMenu         *m menuSocket;
  wxMenu         *m menuDatagramSocket;
  wxMenu         *m menuProtocols;
  wxMenuBar      *m menuBar;
  bool            m busy;

  // any class wishing to process wxWidgets events must use this macro
  DECLARE EVENT TABLE()
};

// --------------------------------------------------------------------------
// constants
// --------------------------------------------------------------------------

// IDs for the controls and the menu commands
enum
{
  // menu items
  CLIENT QUIT = wxID EXIT,
  CLIENT ABOUT = wxID ABOUT,
  CLIENT OPEN = 100,
  CLIENT TEST1,
  CLIENT TEST2,
  CLIENT TEST3,
  CLIENT CLOSE,
#if wxUSE URL
  CLIENT TESTURL,
#endif
  CLIENT DGRAM,

  // id for socket
  SOCKET ID
};

// --------------------------------------------------------------------------
// event tables and other macros for wxWidgets
// --------------------------------------------------------------------------

BEGIN EVENT TABLE(MyFrame, wxFrame)
  EVT MENU(CLIENT QUIT,     MyFrame::OnQuit)
  EVT MENU(CLIENT ABOUT,    MyFrame::OnAbout)
  EVT MENU(CLIENT OPEN,     MyFrame::OnOpenConnection)
  EVT MENU(CLIENT TEST1,    MyFrame::OnTest1)
  EVT MENU(CLIENT TEST2,    MyFrame::OnTest2)
  EVT MENU(CLIENT TEST3,    MyFrame::OnTest3)
  EVT MENU(CLIENT CLOSE,    MyFrame::OnCloseConnection)
  EVT MENU(CLIENT DGRAM,    MyFrame::OnDatagram)
#if wxUSE URL
  EVT MENU(CLIENT TESTURL,  MyFrame::OnTestURL)
#endif
  EVT SOCKET(SOCKET ID,     MyFrame::OnSocketEvent)
END EVENT TABLE()

IMPLEMENT APP(MyApp)

// ==========================================================================
// implementation
// ==========================================================================

// --------------------------------------------------------------------------
// the application class
// --------------------------------------------------------------------------

bool MyApp::OnInit()
{
  // Create the main application window
  MyFrame *frame = new MyFrame();

  // Show it and tell the application that it's our main window
  frame->Show(true);
  SetTopWindow(frame);

  // success
  return true;
}

// --------------------------------------------------------------------------
// main frame
// --------------------------------------------------------------------------

// frame constructor
MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, wxID ANY,
                              ("wxSocket demo: Client"),
                             wxDefaultPosition, wxSize(300, 200))
{
  // Give the frame an icon
  SetIcon(wxICON(mondrian));

  // Make menus
  m menuFile = new wxMenu();
  m menuFile->Append(CLIENT ABOUT,  ("&About...\tCtrl-A"),  ("Show about 
dialog"));
  m menuFile->AppendSeparator();
  m menuFile->Append(CLIENT QUIT,  ("E&xit\tAlt-X"),  ("Quit client"));

  m menuSocket = new wxMenu();
  m menuSocket->Append(CLIENT OPEN,  ("&Open session"),  ("Connect to 
server"));
  m menuSocket->AppendSeparator();
  m menuSocket->Append(CLIENT TEST1,  ("Test &1"),  ("Test basic 
functionality"));
  m menuSocket->Append(CLIENT TEST2,  ("Test &2"),  ("Test ReadMsg and 
WriteMsg"));
  m menuSocket->Append(CLIENT TEST3,  ("Test &3"),  ("Test large data 
transfer"));
  m menuSocket->AppendSeparator();
  m menuSocket->Append(CLIENT CLOSE,  ("&Close session"),  ("Close 
connection"));

  m menuDatagramSocket = new wxMenu();
  m menuDatagramSocket->Append(CLIENT DGRAM,  ("Send Datagram"),  ("Test UDP 
sockets"));

#if wxUSE URL
  m menuProtocols = new wxMenu();
  m menuProtocols->Append(CLIENT TESTURL,  ("Test URL"),  ("Get data from the 
specified URL"));
#endif

  // Append menus to the menubar
  m menuBar = new wxMenuBar();
  m menuBar->Append(m menuFile,  ("&File"));
  m menuBar->Append(m menuSocket,  ("&SocketClient"));
  m menuBar->Append(m menuDatagramSocket,  ("&DatagramSocket"));
#if wxUSE URL
  m menuBar->Append(m menuProtocols,  ("&Protocols"));
#endif
  SetMenuBar(m menuBar);

#if wxUSE STATUSBAR
  // Status bar
  CreateStatusBar(2);
#endif // wxUSE STATUSBAR

  // Make a textctrl for logging
  m text  = new wxTextCtrl(this, wxID ANY,
                            ("Welcome to wxSocket demo: Client\nClient 
ready\n"),
                           wxDefaultPosition, wxDefaultSize,
                           wxTE MULTILINE | wxTE READONLY);

  // Create the socket
  m sock = new wxSocketClient();

  // Setup the event handler and subscribe to most events
  m sock->SetEventHandler(*this, SOCKET ID);
  m sock->SetNotify(wxSOCKET CONNECTION FLAG |
                    wxSOCKET INPUT FLAG |
                    wxSOCKET LOST FLAG);
  m sock->Notify(true);

  m busy = false;
  UpdateStatusBar();
}

MyFrame::~MyFrame()
{
  // No delayed deletion here, as the frame is dying anyway
  delete m sock;
}

// event handlers

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
  // true is to force the frame to close
  Close(true);
}

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
  wxMessageBox( ("wxSocket demo: Client\n(c) 1999 Guillermo Rodriguez 
Garcia\n"),
                ("About Client"),
               wxOK | wxICON INFORMATION, this);
}

void MyFrame::OnOpenConnection(wxCommandEvent& WXUNUSED(event))
{
  wxIPV4address addr;

  m menuSocket->Enable(CLIENT OPEN, false);
  m menuSocket->Enable(CLIENT CLOSE, false);

  // Ask user for server address
  wxString hostname = wxGetTextFromUser(
     ("Enter the address of the wxSocket demo server:"),
     ("Connect ..."),
     ("localhost"));

  addr.Hostname(hostname);
  addr.Service(3000);

  // Mini-tutorial for Connect() :-)
  // ---------------------------
  //
  // There are two ways to use Connect(): blocking and non-blocking,
  // depending on the value passed as the 'wait' (2nd) parameter.
  //
  // Connect(addr, true) will wait until the connection completes,
  // returning true on success and false on failure. This call blocks
  // the GUI (this might be changed in future releases to honour the
  // wxSOCKET BLOCK flag).
  //
  // Connect(addr, false) will issue a nonblocking connection request
  // and return immediately. If the return value is true, then the
  // connection has been already successfully established. If it is
  // false, you must wait for the request to complete, either with
  // WaitOnConnect() or by watching wxSOCKET CONNECTION / LOST
  // events (please read the documentation).
  //
  // WaitOnConnect() itself never blocks the GUI (this might change
  // in the future to honour the wxSOCKET BLOCK flag). This call will
  // return false on timeout, or true if the connection request
  // completes, which in turn might mean:
  //
  //   a) That the connection was successfully established
  //   b) That the connection request failed (for example, because
  //      it was refused by the peer.
  //
  // Use IsConnected() to distinguish between these two.
  //
  // So, in a brief, you should do one of the following things:
  //
  // For blocking Connect:
  //
  //   bool success = client->Connect(addr, true);
  //
  // For nonblocking Connect:
  //
  //   client->Connect(addr, false);
  //
  //   bool waitmore = true;
  //   while (! client->WaitOnConnect(seconds, millis) && waitmore )
  //   {
  //     // possibly give some feedback to the user,
  //     // update waitmore if needed.
  //   }
  //   bool success = client->IsConnected();
  //
  // And that's all :-)

  m text->AppendText( ("\nTrying to connect (timeout = 10 sec) ...\n"));
  m sock->Connect(addr, false);
  m sock->WaitOnConnect(10);

  if (m sock->IsConnected())
    m text->AppendText( ("Succeeded ! Connection established\n"));
  else
  {
    m sock->Close();
    m text->AppendText( ("Failed ! Unable to connect\n"));
    wxMessageBox( ("Can't connect to the specified host"),  ("Alert !"));
  }

  UpdateStatusBar();
}

void MyFrame::OnTest1(wxCommandEvent& WXUNUSED(event))
{
  const wxChar *buf1;
  wxChar       *buf2;
  unsigned char len;

while( 1 )
{
  // Disable socket menu entries (exception: Close Session)
  m busy = true;
  UpdateStatusBar();

  m text->AppendText( ("\n=== Test 1 begins ===\n"));

  // Tell the server which test we are running
  unsigned char c = 0xBE;
  m sock->Write(&c, 1);

  // Send some data and read it back. We know the size of the
  // buffer, so we can specify the exact number of bytes to be
  // sent or received and use the wxSOCKET WAITALL flag. Also,
  // we have disabled menu entries which could interfere with
  // the test, so we can safely avoid the wxSOCKET BLOCK flag.
  //
  // First we send a byte with the length of the string, then
  // we send the string itself (do NOT try to send any integral
  // value larger than a byte "as is" across the network, or
  // you might be in trouble! Ever heard about big and little
  // endian computers?)

  m sock->SetFlags(wxSOCKET WAITALL);

  buf1 =  ("Test string (less than 256 chars!)");
  len  = (unsigned char)((wxStrlen(buf1) + 1) * sizeof(wxChar));
  buf2 = new wxChar[wxStrlen(buf1) + 1];

  m text->AppendText( ("Sending a test buffer to the server ..."));
  m sock->Write(&len, 1);
  m sock->Write(buf1, len);
  m text->AppendText(m sock->Error() ?  ("failed !\n") :  ("done\n"));

  m text->AppendText( ("Receiving the buffer back from server ..."));
  m sock->Read(buf2, len);
  m text->AppendText(m sock->Error() ?  ("failed !\n") :  ("done\n"));

  m text->AppendText( ("Comparing the two buffers ..."));
  if (memcmp(buf1, buf2, len) != 0)
  {
    m text->AppendText( ("failed!\n"));
    m text->AppendText( ("Test 1 failed !\n"));
  }
  else
  {
    m text->AppendText( ("done\n"));
    m text->AppendText( ("Test 1 passed !\n"));
  }
  m text->AppendText( ("=== Test 1 ends ===\n"));

  delete[] buf2;
  m busy = false;
  UpdateStatusBar();

  wxMilliSleep( 32 );
}
}

void MyFrame::OnTest2(wxCommandEvent& WXUNUSED(event))
{
  const wxChar *msg1;
  wxChar *msg2;
  size t len;

  // Disable socket menu entries (exception: Close Session)
  m busy = true;
  UpdateStatusBar();

  m text->AppendText( ("\n=== Test 2 begins ===\n"));

  // Tell the server which test we are running
  unsigned char c = 0xCE;
  m sock->Write(&c, 1);

  // Here we use ReadMsg and WriteMsg to send messages with
  // a header with size information. Also, the reception is
  // event triggered, so we test input events as well.
  //
  // We need to set no flags here (ReadMsg and WriteMsg are
  // not affected by flags)

  m sock->SetFlags(wxSOCKET WAITALL);

  wxString s = wxGetTextFromUser(
     ("Enter an arbitrary string to send to the server:"),
     ("Test 2 ..."),
     ("Yes I like wxWidgets!"));

  msg1 = s.c str();
  len  = (wxStrlen(msg1) + 1) * sizeof(wxChar);
  msg2 = new wxChar[wxStrlen(msg1) + 1];

  m text->AppendText( ("Sending the string with WriteMsg ..."));
  m sock->WriteMsg(msg1, len);
  m text->AppendText(m sock->Error() ?  ("failed !\n") :  ("done\n"));
  m text->AppendText( ("Waiting for an event (timeout = 2 sec)\n"));

  // Wait until data available (will also return if the connection is lost)
  m sock->WaitForRead(2);

  if (m sock->IsData())
  {
    m text->AppendText( ("Reading the string back with ReadMsg ..."));
    m sock->ReadMsg(msg2, len);
    m text->AppendText(m sock->Error() ?  ("failed !\n") :  ("done\n"));
    m text->AppendText( ("Comparing the two buffers ..."));
    if (memcmp(msg1, msg2, len) != 0)
    {
      m text->AppendText( ("failed!\n"));
      m text->AppendText( ("Test 2 failed !\n"));
    }
    else
    {
      m text->AppendText( ("done\n"));
      m text->AppendText( ("Test 2 passed !\n"));
    }
  }
  else
    m text->AppendText( ("Timeout ! Test 2 failed.\n"));

  m text->AppendText( ("=== Test 2 ends ===\n"));

  delete[] msg2;
  m busy = false;
  UpdateStatusBar();
}

void MyFrame::OnTest3(wxCommandEvent& WXUNUSED(event))
{
  char *buf1;
  char *buf2;
  unsigned char len;

  // Disable socket menu entries (exception: Close Session)
  m busy = true;
  UpdateStatusBar();

  m text->AppendText( ("\n=== Test 3 begins ===\n"));

  // Tell the server which test we are running
  unsigned char c = 0xDE;
  m sock->Write(&c, 1);

  // This test also is similar to the first one but it sends a
  // large buffer so that wxSocket is actually forced to split
  // it into pieces and take care of sending everything before
  // returning.

  m sock->SetFlags(wxSOCKET WAITALL);

  // Note that len is in kbytes here!
  len  = 32;
  buf1 = new char[len * 1024];
  buf2 = new char[len * 1024];

  for (int i = 0; i < len * 1024; i ++)
    buf1[i] = (char)(i % 256);

  m text->AppendText( ("Sending a large buffer (32K) to the server ..."));
  m sock->Write(&len, 1);
  m sock->Write(buf1, len * 1024);
  m text->AppendText(m sock->Error() ?  ("failed !\n") :  ("done\n"));

  m text->AppendText( ("Receiving the buffer back from server ..."));
  m sock->Read(buf2, len * 1024);
  m text->AppendText(m sock->Error() ?  ("failed !\n") :  ("done\n"));

  m text->AppendText( ("Comparing the two buffers ..."));
  if (memcmp(buf1, buf2, len) != 0)
  {
    m text->AppendText( ("failed!\n"));
    m text->AppendText( ("Test 3 failed !\n"));
  }
  else
  {
    m text->AppendText( ("done\n"));
    m text->AppendText( ("Test 3 passed !\n"));
  }
  m text->AppendText( ("=== Test 3 ends ===\n"));

  delete[] buf2;
  m busy = false;
  UpdateStatusBar();
}

void MyFrame::OnCloseConnection(wxCommandEvent& WXUNUSED(event))
{
  m sock->Close();
  UpdateStatusBar();
}

void MyFrame::OnDatagram(wxCommandEvent& WXUNUSED(event))
{
  m text->AppendText( ("\n=== Datagram test begins ===\n"));
  m text->AppendText( ("Sorry, not implemented\n"));
  m text->AppendText( ("=== Datagram test ends ===\n"));
}

#if wxUSE URL

void MyFrame::OnTestURL(wxCommandEvent& WXUNUSED(event))
{
  // Note that we are creating a new socket here, so this
  // won't mess with the client/server demo.

  // Ask for the URL
  m text->AppendText( ("\n=== URL test begins ===\n"));
  wxString urlname = wxGetTextFromUser( ("Enter an URL to get"),
                                        ("URL:"),
                                        T("http://localhost"));

  // Parse the URL
  wxURL url(urlname);
  if (url.GetError() != wxURL NOERR)
  {
    m text->AppendText( ("Error: couldn't parse URL\n"));
    m text->AppendText( ("=== URL test ends ===\n"));
    return;
  }

  // Try to get the input stream (connects to the given URL)
  m text->AppendText( ("Trying to establish connection...\n"));
  wxYield();
  wxInputStream *data = url.GetInputStream();
  if (!data)
  {
    m text->AppendText( ("Error: couldn't read from URL\n"));
    m text->AppendText( ("=== URL test ends ===\n"));
    return;
  }

  // Print the contents type and file size
  wxString s;
  s.Printf( ("Contents type: %s\nFile size: %i\nStarting to download...\n"),
             url.GetProtocol().GetContentType().c str(),
             data->GetSize());
  m text->AppendText(s);
  wxYield();

  // Get the data
  wxFile fileTest(wxT("test.url"), wxFile::write);
  wxFileOutputStream sout(fileTest);
  if (!sout.Ok())
  {
    m text->AppendText( ("Error: couldn't open file for output\n"));
    m text->AppendText( ("=== URL test ends ===\n"));
    return;
  }

  data->Read(sout);
  m text->AppendText( ("Results written to file: test.url\n"));
  m text->AppendText( ("Done.\n"));
  m text->AppendText( ("=== URL test ends ===\n"));

  delete data;
}

#endif

void MyFrame::OnSocketEvent(wxSocketEvent& event)
{
  wxString s =  ("OnSocketEvent: ");

  switch(event.GetSocketEvent())
  {
    case wxSOCKET INPUT      : s.Append( ("wxSOCKET INPUT\n")); break;
    case wxSOCKET LOST       : s.Append( ("wxSOCKET LOST\n")); break;
    case wxSOCKET CONNECTION : s.Append( ("wxSOCKET CONNECTION\n")); break;
    default                  : s.Append( ("Unexpected event !\n")); break;
  }

  m text->AppendText(s);
  UpdateStatusBar();
}

// convenience functions

void MyFrame::UpdateStatusBar()
{
  wxString s;

  if (!m sock->IsConnected())
  {
    s.Printf( ("Not connected"));
  }
  else
  {
    wxIPV4address addr;

    m sock->GetPeer(addr);
    s.Printf( ("%s : %d"), (addr.Hostname()).c str(), addr.Service());
  }

#if wxUSE STATUSBAR
  SetStatusText(s, 1);
#endif // wxUSE STATUSBAR

  m menuSocket->Enable(CLIENT OPEN, !m sock->IsConnected() && !m busy);
  m menuSocket->Enable(CLIENT TEST1, m sock->IsConnected() && !m busy);
  m menuSocket->Enable(CLIENT TEST2, m sock->IsConnected() && !m busy);
  m menuSocket->Enable(CLIENT TEST3, m sock->IsConnected() && !m busy);
  m menuSocket->Enable(CLIENT CLOSE, m sock->IsConnected());
}






More information about the wx-users mailing list