+/////////////////////////////////////////////////////////////////////////////
+// Name: samples/sockbase/client.cpp
+// Purpose: Sockets sample for wxBase
+// Author: Lukasz Michalski
+// Modified by:
+// Created: 27.06.2005
+// RCS-ID: $Id$
+// Copyright: (c) 2005 Lukasz Michalski <lmichalski@sf.net>
+// Licence: wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "wx/wx.h"
+#include "wx/socket.h"
+#include "wx/event.h"
+#include "wx/list.h"
+#include "wx/cmdline.h"
+#include "wx/ffile.h"
+#include "wx/datetime.h"
+#include "wx/timer.h"
+#include "wx/thread.h"
+
+const wxEventType wxEVT_WORKER = wxNewEventType();
+#define EVT_WORKER(func) DECLARE_EVENT_TABLE_ENTRY( wxEVT_WORKER, -1, -1, (wxObjectEventFunction) (wxEventFunction) (WorkerEventFunction) & func, (wxObject *) NULL ),
+
+const int timeout_val = 1000;
+
+class WorkerEvent : public wxEvent {
+public:
+ typedef enum {
+ CONNECTING,
+ SENDING,
+ RECEIVING,
+ DISCONNECTING,
+ DONE
+ } evt_type;
+ WorkerEvent(void* pSender, evt_type type)
+ {
+ SetId(-1);
+ SetEventType(wxEVT_WORKER);
+ m_sender = pSender;
+ m_eventType = type;
+ m_isFailed = false;
+ }
+
+ void setFailed() { m_isFailed = true; }
+ bool isFailed() const { return m_isFailed; }
+
+ virtual wxEvent* Clone() const
+ {
+ return new WorkerEvent(*this);
+ }
+ void* m_sender;
+ bool m_isFailed;
+ wxString m_workerIdent;
+ evt_type m_eventType;
+};
+
+typedef void (wxEvtHandler::*WorkerEventFunction)(WorkerEvent&);
+
+class ThreadWorker;
+class EventWorker;
+
+WX_DECLARE_LIST(ThreadWorker, TList);
+WX_DECLARE_LIST(EventWorker, EList);
+
+class Client : public wxApp {
+ DECLARE_EVENT_TABLE();
+public:
+ void RemoveEventWorker(EventWorker* p_worker);
+private:
+ typedef enum
+ {
+ THREADS,
+ EVENTS
+ } workMode;
+
+ typedef enum
+ {
+ SEND_RANDOM,
+ SEND_MESSAGE,
+ STRESS_TEST
+ } sendType;
+
+ workMode m_workMode;
+ sendType m_sendType;
+ wxString m_message;
+ wxString m_host;
+ long m_stressWorkers;
+
+ virtual bool OnInit();
+ virtual int OnRun();
+ virtual int OnExit();
+ void OnInitCmdLine(wxCmdLineParser& pParser);
+ bool OnCmdLineParsed(wxCmdLineParser& pParser);
+ void OnWorkerEvent(WorkerEvent& pEvent);
+ void OnTimerEvent(wxTimerEvent& pEvent);
+
+ void StartWorker(workMode pMode, const wxString& pMessage);
+ void StartWorker(workMode pMode);
+ char* CreateBuffer(int *msgsize);
+
+ void dumpStatistics();
+
+ TList m_threadWorkers;
+ EList m_eventWorkers;
+
+ unsigned m_statConnecting;
+ unsigned m_statSending;
+ unsigned m_statReceiving;
+ unsigned m_statDisconnecting;
+ unsigned m_statDone;
+ unsigned m_statFailed;
+
+ wxTimer mTimer;
+};
+
+DECLARE_APP(Client);
+
+class ThreadWorker : public wxThread
+{
+public:
+ ThreadWorker(const wxString& p_host, char* p_buf, int p_size);
+ virtual ExitCode Entry();
+private:
+ wxString m_host;
+ wxSocketClient* m_clientSocket;
+ char* m_inbuf;
+ char* m_outbuf;
+ int m_outsize;
+ int m_insize;
+ wxString m_workerIdent;
+};
+
+class EventWorker : public wxEvtHandler
+{
+ DECLARE_EVENT_TABLE();
+public:
+ EventWorker(const wxString& p_host, char* p_buf, int p_size);
+ void Run();
+ virtual ~EventWorker();
+private:
+ wxString m_host;
+ wxSocketClient* m_clientSocket;
+ char* m_inbuf;
+ char* m_outbuf;
+ int m_outsize;
+ int m_written;
+ int m_insize;
+ int m_readed;
+
+ WorkerEvent::evt_type m_currentType;
+ bool m_doneSent;
+ wxIPV4address m_localaddr;
+
+ void OnSocketEvent(wxSocketEvent& pEvent);
+ void SendEvent(bool failed);
+};
+
+/******************* Implementation ******************/
+IMPLEMENT_APP_CONSOLE(Client);
+
+#include <wx/listimpl.cpp>
+WX_DEFINE_LIST(TList);
+WX_DEFINE_LIST(EList);
+
+wxString
+CreateIdent(const wxIPV4address& addr)
+{
+ return wxString::Format(wxT("%s:%d"),addr.IPAddress().c_str(),addr.Service());
+}
+
+void
+Client::OnInitCmdLine(wxCmdLineParser& pParser)
+{
+ wxApp::OnInitCmdLine(pParser);
+ pParser.AddSwitch(wxT("e"),wxT("event"),_("Use event based worker (default)"),wxCMD_LINE_PARAM_OPTIONAL);
+ pParser.AddSwitch(wxT("t"),wxT("thread"),_("Use thread based worker"),wxCMD_LINE_PARAM_OPTIONAL);
+ pParser.AddSwitch(wxT("r"),wxT("random"),_("Send radnom data (default)"),wxCMD_LINE_PARAM_OPTIONAL);
+ pParser.AddOption(wxT("m"),wxT("message"),_("Send message from <str>"),wxCMD_LINE_VAL_STRING,wxCMD_LINE_PARAM_OPTIONAL);
+ pParser.AddOption(wxT("f"),wxT("file"),_("Send contents of <file>"),wxCMD_LINE_VAL_STRING,wxCMD_LINE_PARAM_OPTIONAL);
+ pParser.AddOption(wxT("H"),wxT("hostname"),_("IP or name of host to connect to"),wxCMD_LINE_VAL_STRING,wxCMD_LINE_PARAM_OPTIONAL);
+ pParser.AddOption(wxT("s"),wxT("stress"),_("stress test with <num> concurrent connections"),wxCMD_LINE_VAL_NUMBER,wxCMD_LINE_PARAM_OPTIONAL);
+}
+
+
+bool
+Client::OnCmdLineParsed(wxCmdLineParser& pParser)
+{
+ wxString fname;
+ m_workMode = EVENTS;
+ m_stressWorkers = 50;
+
+ if (pParser.Found(_("verbose")))
+ {
+ wxLog::AddTraceMask(wxT("wxSocket"));
+ wxLog::AddTraceMask(wxT("epolldispatcher"));
+ wxLog::AddTraceMask(wxT("selectdispatcher"));
+ wxLog::AddTraceMask(wxT("thread"));
+ wxLog::AddTraceMask(wxT("events"));
+ }
+
+ if (pParser.Found(wxT("t")))
+ m_workMode = THREADS;
+ m_sendType = SEND_RANDOM;
+
+ if (pParser.Found(wxT("m"),&m_message))
+ m_sendType = SEND_MESSAGE;
+ else if (pParser.Found(wxT("f"),&fname))
+ {
+ wxFFile file(fname);
+ if (!file.IsOpened()) {
+ wxLogError(wxT("Cannot open file %s"),fname.c_str());
+ return false;
+ };
+ if (!file.ReadAll(&m_message)) {
+ wxLogError(wxT("Cannot read conten of file %s"),fname.c_str());
+ return false;
+ };
+ m_sendType = SEND_MESSAGE;
+ };
+
+ if (pParser.Found(wxT("s"),&m_stressWorkers))
+ m_sendType = STRESS_TEST;
+
+ m_host = wxT("127.0.0.1");
+ pParser.Found(wxT("H"),&m_host);
+ return wxApp::OnCmdLineParsed(pParser);
+};
+
+bool
+Client::OnInit()
+{
+ if (!wxApp::OnInit())
+ return false;
+ srand(wxDateTime::Now().GetTicks());
+ mTimer.SetOwner(this);
+ m_statConnecting = 0;
+ m_statSending = 0;
+ m_statReceiving = 0;
+ m_statDisconnecting = 0;
+ m_statDone = 0;
+ m_statFailed = 0;
+ return true;
+}
+
+int
+Client::OnRun()
+{
+ switch(m_sendType)
+ {
+ case STRESS_TEST:
+ switch(m_workMode)
+ {
+ case THREADS:
+ for (int i = 0; i < m_stressWorkers; i++) {
+ if (m_message.empty())
+ StartWorker(THREADS);
+ else
+ StartWorker(THREADS, m_message);
+ }
+ break;
+ case EVENTS:
+ for (int i = 0; i < m_stressWorkers; i++) {
+ if (m_message.empty())
+ StartWorker(EVENTS);
+ else
+ StartWorker(EVENTS, m_message);
+ }
+ break;
+ default:
+ for (int i = 0; i < m_stressWorkers; i++) {
+ if (m_message.empty())
+ StartWorker(i % 5 == 0 ? THREADS : EVENTS);
+ else
+ StartWorker(i % 5 == 0 ? THREADS : EVENTS, m_message);
+ }
+ break;
+ }
+ break;
+ case SEND_MESSAGE:
+ StartWorker(m_workMode,m_message);
+ break;
+ case SEND_RANDOM:
+ StartWorker(m_workMode);
+ break;
+ }
+ mTimer.Start(timeout_val,true);
+ return wxApp::OnRun();
+}
+
+int
+Client::OnExit()
+{
+ for(EList::compatibility_iterator it = m_eventWorkers.GetFirst(); it ; it->GetNext()) {
+ delete it->GetData();
+ }
+ return 0;
+}
+
+// Create buffer to be sent by client. Buffer contains test indicator
+// message size and place for data
+// msgsize parameter contains size of data in bytes and
+// if input value does not fit into 250 bytes then
+// on exit is updated to new value that is multiply of 1024 bytes
+char*
+Client::CreateBuffer(int* msgsize)
+{
+ int bufsize = 0;
+ char* buf;
+ //if message should have more than 256 bytes then set it as
+ //test3 for compatibility with GUI server sample
+ if ((*msgsize) > 250)
+ {
+ //send at least one kb of data
+ int size = (*msgsize)/1024 + 1;
+ //returned buffer will contain test indicator, message size in kb and data
+ bufsize = size*1024+2;
+ buf = new char[bufsize];
+ buf[0] = 0xDE; //second byte contains size in kilobytes
+ buf[1] = (char)(size);
+ *msgsize = size*1024;
+ }
+ else
+ {
+ //returned buffer will contain test indicator, message size in kb and data
+ bufsize = (*msgsize)+2;
+ buf = new char[bufsize];
+ buf[0] = 0xBE; //second byte contains size in bytes
+ buf[1] = (char)(*msgsize);
+ }
+ return buf;
+}
+
+void
+Client::StartWorker(workMode pMode) {
+ int msgsize = 1 + (int) (250000.0 * (rand() / (RAND_MAX + 1.0)));
+ char* buf = CreateBuffer(&msgsize);
+
+ //fill data part of buffer with random bytes
+ for (int i = 2; i < (msgsize); i++) {
+ buf[i] = i % 256;
+ }
+
+ if (pMode == THREADS) {
+ ThreadWorker* c = new ThreadWorker(m_host,buf,msgsize+2);
+ if (c->Create() != wxTHREAD_NO_ERROR) {
+ wxLogError(wxT("Cannot create more threads"));
+ } else {
+ c->Run();
+ m_threadWorkers.Append(c);
+ }
+ } else {
+ EventWorker* e = new EventWorker(m_host,buf,msgsize+2);
+ e->Run();
+ m_eventWorkers.Append(e);
+ }
+ m_statConnecting++;
+}
+
+void
+Client::StartWorker(workMode pMode, const wxString& pMessage) {
+ char* tmpbuf = strdup(pMessage.mb_str());
+ int msgsize = strlen(tmpbuf);
+ char* buf = CreateBuffer(&msgsize);
+ memset(buf+2,0x0,msgsize);
+ memcpy(buf+2,tmpbuf,msgsize);
+ free(tmpbuf);
+
+ if (pMode == THREADS) {
+ ThreadWorker* c = new ThreadWorker(m_host,buf,msgsize+2);
+ if (c->Create() != wxTHREAD_NO_ERROR) {
+ wxLogError(wxT("Cannot create more threads"));
+ } else {
+ c->Run();
+ m_threadWorkers.Append(c);
+ }
+ } else {
+ EventWorker* e = new EventWorker(m_host,buf,msgsize+2);
+ e->Run();
+ m_eventWorkers.Append(e);
+ }
+ m_statConnecting++;
+}
+
+void
+Client::OnWorkerEvent(WorkerEvent& pEvent) {
+ switch (pEvent.m_eventType) {
+ case WorkerEvent::CONNECTING:
+ if (pEvent.isFailed())
+ {
+ m_statConnecting--;
+ m_statFailed++;
+ }
+ break;
+ case WorkerEvent::SENDING:
+ if (pEvent.isFailed())
+ {
+ m_statFailed++;
+ m_statSending--;
+ }
+ else
+ {
+ m_statConnecting--;
+ m_statSending++;
+ }
+ break;
+ case WorkerEvent::RECEIVING:
+ if (pEvent.isFailed())
+ {
+ m_statReceiving--;
+ m_statFailed++;
+ }
+ else
+ {
+ m_statSending--;
+ m_statReceiving++;
+ }
+ break;
+ case WorkerEvent::DISCONNECTING:
+ if (pEvent.isFailed())
+ {
+ m_statDisconnecting--;
+ m_statFailed++;
+ }
+ else
+ {
+ m_statReceiving--;
+ m_statDisconnecting++;
+ }
+ break;
+ case WorkerEvent::DONE:
+ m_statDone++;
+ m_statDisconnecting--;
+ break;
+ };
+
+ if (pEvent.isFailed() || pEvent.m_eventType == WorkerEvent::DONE)
+ {
+ for(TList::compatibility_iterator it = m_threadWorkers.GetFirst(); it ; it = it->GetNext()) {
+ if (it->GetData() == pEvent.m_sender) {
+ m_threadWorkers.DeleteNode(it);
+ break;
+ }
+ }
+ for(EList::compatibility_iterator it = m_eventWorkers.GetFirst(); it ; it = it->GetNext())
+ {
+ if (it->GetData() == pEvent.m_sender) {
+ delete it->GetData();
+ m_eventWorkers.DeleteNode(it);
+ break;
+ }
+ }
+ if ((m_threadWorkers.GetCount() == 0) && (m_eventWorkers.GetCount() == 0))
+ {
+ mTimer.Stop();
+ dumpStatistics();
+ wxSleep(2);
+ ExitMainLoop();
+ }
+ else
+ {
+ mTimer.Start(timeout_val,true);
+ }
+ }
+}
+
+void
+Client::RemoveEventWorker(EventWorker* p_worker) {
+ for(EList::compatibility_iterator it = m_eventWorkers.GetFirst(); it ; it = it->GetNext()) {
+ if (it->GetData() == p_worker) {
+ //wxLogDebug(wxT("Deleting event worker"));
+ delete it->GetData();
+ m_eventWorkers.DeleteNode(it);
+ return;
+ }
+ }
+}
+
+void
+Client::dumpStatistics() {
+ wxString msg(
+ wxString::Format(_("Connecting:\t%d\nSending\t\t%d\nReceiving\t%d\nDisconnecting:\t%d\nDone:\t\t%d\nFailed:\t\t%d\n"),
+ m_statConnecting,
+ m_statSending,
+ m_statReceiving,
+ m_statDisconnecting,
+ m_statDone,
+ m_statFailed
+ ));
+
+ wxLogMessage(wxT("Current status:\n%s\n"),msg.c_str());
+}
+
+void
+Client::OnTimerEvent(wxTimerEvent&) {
+ dumpStatistics();
+}
+
+BEGIN_EVENT_TABLE(Client,wxEvtHandler)
+ EVT_WORKER(Client::OnWorkerEvent)
+ EVT_TIMER(wxID_ANY,Client::OnTimerEvent)
+END_EVENT_TABLE()
+
+
+
+EventWorker::EventWorker(const wxString& p_host, char* p_buf, int p_size)
+ : m_host(p_host),
+ m_outbuf(p_buf),
+ m_outsize(p_size),
+ m_written(0),
+ m_readed(0)
+{
+ m_clientSocket = new wxSocketClient(wxSOCKET_NOWAIT);
+ m_clientSocket->SetEventHandler(*this);
+ m_insize = m_outsize - 2;
+ m_inbuf = new char[m_insize];
+}
+
+void
+EventWorker::Run() {
+ wxIPV4address ca;
+ ca.Hostname(m_host);
+ ca.Service(3000);
+ m_clientSocket->SetNotify(wxSOCKET_CONNECTION_FLAG|wxSOCKET_LOST_FLAG|wxSOCKET_OUTPUT_FLAG|wxSOCKET_INPUT_FLAG);
+ m_clientSocket->Notify(true);
+ m_currentType = WorkerEvent::CONNECTING;
+ m_doneSent = false;
+ //wxLogMessage(wxT("EventWorker: Connecting....."));
+ m_clientSocket->Connect(ca,false);
+}
+
+void
+EventWorker::OnSocketEvent(wxSocketEvent& pEvent) {
+ switch(pEvent.GetSocketEvent()) {
+ case wxSOCKET_INPUT:
+ //wxLogDebug(wxT("EventWorker: INPUT"));
+ do {
+ if (m_readed == m_insize)
+ return; //event already posted
+ m_clientSocket->Read(m_inbuf + m_readed, m_insize - m_readed);
+ if (m_clientSocket->Error())
+ {
+ if (m_clientSocket->LastError() != wxSOCKET_WOULDBLOCK)
+ {
+ wxLogError(wxT("%s: read error"),CreateIdent(m_localaddr).c_str());
+ SendEvent(true);
+ }
+ }
+
+ m_readed += m_clientSocket->LastCount();
+ //wxLogDebug(wxT("EventWorker: readed %d bytes, %d bytes to do"),m_clientSocket->LastCount(), m_insize - m_readed);
+ if (m_readed == m_insize)
+ {
+ if (!memcmp(m_inbuf,m_outbuf,m_insize)) {
+ wxLogError(wxT("%s: data mismatch"),CreateIdent(m_localaddr).c_str());
+ SendEvent(true);
+ }
+ m_currentType = WorkerEvent::DISCONNECTING;
+ wxLogDebug(wxT("%s: DISCONNECTING"),CreateIdent(m_localaddr).c_str());
+ SendEvent(false);
+
+ //wxLogDebug(wxT("EventWorker %p closing"),this);
+ m_clientSocket->Close();
+
+ m_currentType = WorkerEvent::DONE;
+ wxLogDebug(wxT("%s: DONE"),CreateIdent(m_localaddr).c_str());
+ SendEvent(false);
+ }
+ } while (!m_clientSocket->Error());
+ break;
+ case wxSOCKET_OUTPUT:
+ //wxLogDebug(wxT("EventWorker: OUTPUT"));
+ do {
+ if (m_written == m_outsize)
+ return;
+ if (m_written == 0)
+ {
+ m_currentType = WorkerEvent::SENDING;
+ wxLogDebug(wxT("%s: SENDING"),CreateIdent(m_localaddr).c_str());
+ }
+ m_clientSocket->Write(m_outbuf + m_written, m_outsize - m_written);
+ if (m_clientSocket->Error())
+ {
+ if (m_clientSocket->LastError() != wxSOCKET_WOULDBLOCK) {
+ wxLogError(wxT("%s: Write error"),CreateIdent(m_localaddr).c_str());
+ SendEvent(true);
+ }
+ }
+ m_written += m_clientSocket->LastCount();
+ if (m_written != m_outsize)
+ {
+ //wxLogDebug(wxT("EventWorker: written %d bytes, %d bytes to do"),m_clientSocket->LastCount(),m_outsize - m_written);
+ }
+ else
+ {
+ //wxLogDebug(wxT("EventWorker %p SENDING->RECEIVING"),this);
+ m_currentType = WorkerEvent::RECEIVING;
+ wxLogDebug(wxT("%s: RECEIVING"),CreateIdent(m_localaddr).c_str());
+ SendEvent(false);
+ }
+ } while(!m_clientSocket->Error());
+ break;
+ case wxSOCKET_CONNECTION:
+ {
+ //wxLogMessage(wxT("EventWorker: got connection"));
+ wxLogMessage(wxT("%s: starting writing message (2 bytes for signature and %d bytes of data to write)"),CreateIdent(m_localaddr).c_str(),m_outsize-2);
+ if (!m_clientSocket->GetLocal(m_localaddr))
+ wxLogError(_("Cannot get peer data for socket %p"),m_clientSocket);
+ m_currentType = WorkerEvent::SENDING;
+ wxLogDebug(wxT("%s: CONNECTING"),CreateIdent(m_localaddr).c_str());
+ SendEvent(false);
+ }
+ break;
+ case wxSOCKET_LOST:
+ {
+ wxLogError(_("%s: connection lost"),CreateIdent(m_localaddr).c_str());
+ SendEvent(true);
+ }
+ break;
+ }
+}
+
+void
+EventWorker::SendEvent(bool failed) {
+ if (m_doneSent)
+ return;
+ WorkerEvent e(this,m_currentType);
+ if (failed) e.setFailed();
+ wxGetApp().AddPendingEvent(e);
+ m_doneSent = failed || m_currentType == WorkerEvent::DONE;
+};
+
+EventWorker::~EventWorker() {
+ m_clientSocket->Destroy();
+ delete [] m_outbuf;
+ delete [] m_inbuf;
+}
+
+BEGIN_EVENT_TABLE(EventWorker,wxEvtHandler)
+ EVT_SOCKET(wxID_ANY,EventWorker::OnSocketEvent)
+END_EVENT_TABLE()
+
+
+ThreadWorker::ThreadWorker(const wxString& p_host, char* p_buf, int p_size)
+ : wxThread(wxTHREAD_DETACHED),
+ m_host(p_host),
+ m_outbuf(p_buf),
+ m_outsize(p_size)
+{
+ m_clientSocket = new wxSocketClient(wxSOCKET_BLOCK|wxSOCKET_WAITALL);
+ m_insize = m_outsize - 2;
+ m_inbuf = new char[m_insize];
+}
+
+wxThread::ExitCode ThreadWorker::Entry()
+{
+ wxIPV4address ca;
+ ca.Hostname(m_host);
+ ca.Service(5678);
+ //wxLogDebug(wxT("ThreadWorker: Connecting....."));
+ m_clientSocket->SetTimeout(60);
+ bool failed = false;
+ WorkerEvent::evt_type etype = WorkerEvent::CONNECTING;
+ if (!m_clientSocket->Connect(ca)) {
+ wxLogError(wxT("Cannot connect to %s:%d"),ca.IPAddress().c_str(), ca.Service());
+ failed = true;
+ } else {
+ //wxLogMessage(wxT("ThreadWorker: Connected. Sending %d bytes of data"),m_outsize);
+ etype = WorkerEvent::SENDING;
+ WorkerEvent e(this,etype);
+ wxGetApp().AddPendingEvent(e);
+ int to_process = m_outsize;
+ do {
+ m_clientSocket->Write(m_outbuf,m_outsize);
+ if (m_clientSocket->Error()) {
+ wxLogError(wxT("ThreadWorker: Write error"));
+ failed = true;
+ }
+ to_process -= m_clientSocket->LastCount();
+ //wxLogDebug(wxT("EventWorker: written %d bytes, %d bytes to do"),m_clientSocket->LastCount(),to_process);
+ } while(!m_clientSocket->Error() && to_process != 0);
+
+ if (!failed) {
+ etype = WorkerEvent::RECEIVING;
+ WorkerEvent e(this,etype);
+ wxGetApp().AddPendingEvent(e);
+ to_process = m_insize;
+ do {
+ m_clientSocket->Read(m_inbuf,m_insize);
+ if (m_clientSocket->Error()) {
+ wxLogError(wxT("ThreadWorker: Read error"));
+ failed = true;
+ break;
+ }
+ to_process -= m_clientSocket->LastCount();
+ //wxLogDebug(wxT("EventWorker: readed %d bytes, %d bytes to do"),m_clientSocket->LastCount(),to_process);
+ } while(!m_clientSocket->Error() && to_process != 0);
+ }
+
+ char* outdat = (char*)m_outbuf+2;
+ if (!failed && (memcmp(m_inbuf,outdat,m_insize) != 0))
+ {
+ wxLogError(wxT("Data mismatch"));
+ failed = true;
+ }
+ }
+ //wxLogDebug(wxT("ThreadWorker: Finished"));
+ if (!failed) {
+ etype = WorkerEvent::DISCONNECTING;
+ WorkerEvent e(this,etype);
+ wxGetApp().AddPendingEvent(e);
+ };
+ m_clientSocket->Close();
+ m_clientSocket->Destroy();
+ m_clientSocket = NULL;
+ delete [] m_outbuf;
+ delete [] m_inbuf;
+ if (!failed)
+ etype = WorkerEvent::DONE;
+ WorkerEvent e(this,etype);
+ if (failed) e.setFailed();
+ wxGetApp().AddPendingEvent(e);
+ return 0;
+}
+