git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@60945 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			735 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			735 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/////////////////////////////////////////////////////////////////////////////
 | 
						|
// 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()
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    switch(m_sendType)
 | 
						|
    {
 | 
						|
        case STRESS_TEST:
 | 
						|
            switch(m_workMode)
 | 
						|
            {
 | 
						|
                case THREADS:
 | 
						|
                    for (i = 0; i < m_stressWorkers; i++) {
 | 
						|
                        if (m_message.empty())
 | 
						|
                            StartWorker(THREADS);
 | 
						|
                        else
 | 
						|
                            StartWorker(THREADS, m_message);
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
                case EVENTS:
 | 
						|
                    for (i = 0; i < m_stressWorkers; i++) {
 | 
						|
                        if (m_message.empty())
 | 
						|
                            StartWorker(EVENTS);
 | 
						|
                        else
 | 
						|
                            StartWorker(EVENTS, m_message);
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
                default:
 | 
						|
                    for (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] = (unsigned char)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] = (unsigned char)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 = wxStrdup(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 it2 = m_eventWorkers.GetFirst(); it2 ; it2 = it2->GetNext())
 | 
						|
        {
 | 
						|
            if (it2->GetData() == pEvent.m_sender) {
 | 
						|
                delete it2->GetData();
 | 
						|
                m_eventWorkers.DeleteNode(it2);
 | 
						|
                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;
 | 
						|
}
 | 
						|
 |