baseserver.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: samples/sockbase/client.cpp
  3. // Purpose: Sockets sample for wxBase
  4. // Author: Lukasz Michalski
  5. // Modified by:
  6. // Created: 27.06.2005
  7. // Copyright: (c) 2005 Lukasz Michalski <lmichalski@user.sourceforge.net>
  8. // Licence: wxWindows licence
  9. /////////////////////////////////////////////////////////////////////////////
  10. // ============================================================================
  11. // declarations
  12. // ============================================================================
  13. // ----------------------------------------------------------------------------
  14. // headers
  15. // ----------------------------------------------------------------------------
  16. #include "wx/wx.h"
  17. #include "wx/socket.h"
  18. #include "wx/event.h"
  19. #include "wx/list.h"
  20. #include "wx/cmdline.h"
  21. #include "wx/datetime.h"
  22. #include "wx/timer.h"
  23. #include "wx/thread.h"
  24. const char *GetSocketErrorMsg(int pSockError)
  25. {
  26. switch(pSockError)
  27. {
  28. case wxSOCKET_NOERROR:
  29. return "wxSOCKET_NOERROR";
  30. case wxSOCKET_INVOP:
  31. return "wxSOCKET_INVOP";
  32. case wxSOCKET_IOERR:
  33. return "wxSOCKET_IOERR";
  34. case wxSOCKET_INVADDR:
  35. return "wxSOCKET_INVADDR";
  36. case wxSOCKET_NOHOST:
  37. return "wxSOCKET_NOHOST";
  38. case wxSOCKET_INVPORT:
  39. return "wxSOCKET_INVPORT";
  40. case wxSOCKET_WOULDBLOCK:
  41. return "wxSOCKET_WOULDBLOCK";
  42. case wxSOCKET_TIMEDOUT:
  43. return "wxSOCKET_TIMEDOUT";
  44. case wxSOCKET_MEMERR:
  45. return "wxSOCKET_MEMERR";
  46. default:
  47. return "Unknown";
  48. }
  49. }
  50. //event sent by workers to server class
  51. //after client is served
  52. const wxEventType wxEVT_WORKER = wxNewEventType();
  53. #define EVT_WORKER(func) DECLARE_EVENT_TABLE_ENTRY( wxEVT_WORKER, -1, -1, (wxObjectEventFunction) (wxEventFunction) (WorkerEventFunction) & func, (wxObject *) NULL ),
  54. class WorkerEvent : public wxEvent
  55. {
  56. public:
  57. WorkerEvent(void* pSender)
  58. {
  59. SetId(-1);
  60. SetEventType(wxEVT_WORKER);
  61. m_sender = pSender;
  62. m_exit = false;
  63. m_workerFailed = false;
  64. }
  65. virtual wxEvent* Clone() const
  66. {
  67. return new WorkerEvent(*this);
  68. }
  69. void* m_sender;
  70. bool m_exit;
  71. bool m_workerFailed;
  72. };
  73. typedef void (wxEvtHandler::*WorkerEventFunction)(WorkerEvent&);
  74. class ThreadWorker;
  75. class EventWorker;
  76. WX_DECLARE_LIST(ThreadWorker, TList);
  77. WX_DECLARE_LIST(EventWorker, EList);
  78. //main server class contains listening socket
  79. //and list of two type worker classes that serve clients
  80. class Server : public wxApp
  81. {
  82. wxDECLARE_EVENT_TABLE();
  83. public:
  84. Server() : m_maxConnections(-1) {}
  85. ~Server() {}
  86. private:
  87. enum WorkMode
  88. {
  89. MIXED,
  90. THREADS,
  91. EVENTS
  92. };
  93. virtual bool OnInit();
  94. virtual int OnExit();
  95. void OnInitCmdLine(wxCmdLineParser& pParser);
  96. bool OnCmdLineParsed(wxCmdLineParser& pParser);
  97. void OnSocketEvent(wxSocketEvent& pEvent);
  98. void OnWorkerEvent(WorkerEvent& pEvent);
  99. void OnTimerEvent(wxTimerEvent& pEvent);
  100. void DumpStatistics();
  101. TList m_threadWorkers;
  102. EList m_eventWorkers;
  103. WorkMode m_workMode;
  104. wxSocketServer* m_listeningSocket;
  105. // statistics
  106. unsigned m_threadWorkersCreated;
  107. unsigned m_threadWorkersDone;
  108. unsigned m_threadWorkersFailed;
  109. unsigned m_maxThreadWorkers;
  110. unsigned m_eventWorkersCreated;
  111. unsigned m_eventWorkersDone;
  112. unsigned m_eventWorkersFailed;
  113. unsigned m_maxEventWorkers;
  114. long int m_maxConnections;
  115. unsigned short m_port;
  116. wxTimer mTimer;
  117. };
  118. DECLARE_APP(Server);
  119. // just some common things shared between ThreadWorker and EventWorker
  120. class WorkerBase
  121. {
  122. protected:
  123. // outputs log message with IP and TCP port number prepended
  124. void LogWorker(const wxString& msg, wxLogLevel level = wxLOG_Info)
  125. {
  126. wxLogGeneric(level,
  127. "%s:%d %s", m_peer.IPAddress(), m_peer.Service(), msg);
  128. }
  129. wxIPV4address m_peer;
  130. };
  131. //thread based worker reads signature and all data first from connected client
  132. //and resends data to client after reading
  133. class ThreadWorker : public wxThread, private WorkerBase
  134. {
  135. public:
  136. ThreadWorker(wxSocketBase* pSocket);
  137. virtual ExitCode Entry();
  138. private:
  139. wxSocketBase* m_socket;
  140. };
  141. //event based worker reads signature and creates buffer for incoming data.
  142. //When part of data arrives this worker resends it as soon as possible.
  143. class EventWorker : public wxEvtHandler, private WorkerBase
  144. {
  145. public:
  146. EventWorker(wxSocketBase* pSock);
  147. virtual ~EventWorker();
  148. private:
  149. wxSocketBase* m_socket;
  150. unsigned char m_signature[2];
  151. char* m_inbuf;
  152. int m_infill;
  153. int m_size;
  154. char* m_outbuf;
  155. int m_outfill;
  156. int m_written;
  157. void OnSocketEvent(wxSocketEvent& pEvent);
  158. void DoWrite();
  159. void DoRead();
  160. wxDECLARE_EVENT_TABLE();
  161. };
  162. /******************* Implementation ******************/
  163. IMPLEMENT_APP_CONSOLE(Server)
  164. #include <wx/listimpl.cpp>
  165. WX_DEFINE_LIST(TList);
  166. WX_DEFINE_LIST(EList);
  167. void
  168. Server::OnInitCmdLine(wxCmdLineParser& pParser)
  169. {
  170. wxApp::OnInitCmdLine(pParser);
  171. pParser.AddSwitch("t","threads","Use thread based workers only");
  172. pParser.AddSwitch("e","events","Use event based workers only");
  173. pParser.AddOption("m","max","Exit after <n> connections",
  174. wxCMD_LINE_VAL_NUMBER);
  175. pParser.AddOption("p","port","listen on given port (default 3000)",
  176. wxCMD_LINE_VAL_NUMBER);
  177. }
  178. void
  179. Server::DumpStatistics()
  180. {
  181. wxString mode;
  182. switch(m_workMode)
  183. {
  184. case EVENTS:
  185. mode = "Event based workers";
  186. break;
  187. case THREADS:
  188. mode = "Thread based workers";
  189. break;
  190. case MIXED:
  191. mode = "Event and thread based workers";
  192. break;
  193. }
  194. wxLogMessage("Server mode: %s",mode);
  195. wxLogMessage("\t\t\t\tThreads\tEvents\tTotal");
  196. wxLogMessage("Workers created:\t\t%d\t%d\t%d",
  197. m_threadWorkersCreated,
  198. m_eventWorkersCreated,
  199. m_threadWorkersCreated + m_eventWorkersCreated);
  200. wxLogMessage("Max concurrent workers:\t%d\t%d\t%d",
  201. m_maxThreadWorkers,
  202. m_maxEventWorkers,
  203. m_maxThreadWorkers + m_maxEventWorkers);
  204. wxLogMessage("Workers failed:\t\t%d\t%d\t%d",
  205. m_threadWorkersFailed,
  206. m_eventWorkersFailed,
  207. m_threadWorkersFailed + m_eventWorkersFailed);
  208. wxLogMessage("Workers done:\t\t%d\t%d\t%d",
  209. m_threadWorkersDone,
  210. m_eventWorkersDone,
  211. m_threadWorkersDone + m_eventWorkersDone);
  212. if ((int)(m_threadWorkersDone+m_eventWorkersDone) == m_maxConnections)
  213. {
  214. wxLogMessage("%ld connection(s) served, exiting",m_maxConnections);
  215. ExitMainLoop();
  216. }
  217. }
  218. bool
  219. Server::OnCmdLineParsed(wxCmdLineParser& pParser)
  220. {
  221. if (pParser.Found("verbose"))
  222. {
  223. wxLog::AddTraceMask("wxSocket");
  224. wxLog::AddTraceMask("epolldispatcher");
  225. wxLog::AddTraceMask("selectdispatcher");
  226. wxLog::AddTraceMask("thread");
  227. wxLog::AddTraceMask("events");
  228. wxLog::AddTraceMask("timer");
  229. }
  230. if (pParser.Found("m",&m_maxConnections))
  231. {
  232. wxLogMessage("%ld connection(s) to exit",m_maxConnections);
  233. }
  234. long port;
  235. if (pParser.Found("p", &port))
  236. {
  237. if ( port <= 0 || port > USHRT_MAX )
  238. {
  239. wxLogError("Invalid port number %ld, must be in 0..%u range.",
  240. port, USHRT_MAX);
  241. return false;
  242. }
  243. m_port = static_cast<unsigned short>(port);
  244. wxLogMessage("Will listen on port %u", m_port);
  245. }
  246. if (pParser.Found("t"))
  247. m_workMode = THREADS;
  248. else if (pParser.Found("e"))
  249. m_workMode = EVENTS;
  250. else
  251. m_workMode = MIXED;
  252. return wxApp::OnCmdLineParsed(pParser);
  253. }
  254. bool Server::OnInit()
  255. {
  256. wxLog* logger = new wxLogStderr();
  257. wxLog::SetActiveTarget(logger);
  258. m_port = 3000;
  259. //send interesting things to console
  260. if (!wxApp::OnInit())
  261. return false;
  262. //setup listening socket
  263. wxIPV4address la;
  264. la.Service(m_port);
  265. m_listeningSocket = new wxSocketServer(la,wxSOCKET_NOWAIT|wxSOCKET_REUSEADDR);
  266. m_listeningSocket->SetEventHandler(*this);
  267. m_listeningSocket->SetNotify(wxSOCKET_CONNECTION_FLAG);
  268. m_listeningSocket->Notify(true);
  269. if (!m_listeningSocket->IsOk())
  270. {
  271. wxLogError("Cannot bind listening socket");
  272. return false;
  273. }
  274. m_threadWorkersCreated = 0;
  275. m_threadWorkersDone = 0;
  276. m_threadWorkersFailed = 0;
  277. m_maxThreadWorkers = 0;
  278. m_eventWorkersCreated = 0;
  279. m_eventWorkersDone = 0;
  280. m_eventWorkersFailed = 0;
  281. m_maxEventWorkers = 0;
  282. wxLogMessage("Server listening at port %u, waiting for connections", m_port);
  283. return true;
  284. }
  285. int Server::OnExit()
  286. {
  287. for ( TList::compatibility_iterator it = m_threadWorkers.GetFirst();
  288. it;
  289. it = it->GetNext() )
  290. {
  291. it->GetData()->Wait();
  292. delete it->GetData();
  293. }
  294. for ( EList::compatibility_iterator it2 = m_eventWorkers.GetFirst();
  295. it2;
  296. it2->GetNext() )
  297. {
  298. delete it2->GetData();
  299. }
  300. m_threadWorkers.Clear();
  301. m_eventWorkers.Clear();
  302. m_listeningSocket->Destroy();
  303. return 0;
  304. }
  305. void Server::OnSocketEvent(wxSocketEvent& pEvent)
  306. {
  307. switch(pEvent.GetSocketEvent())
  308. {
  309. case wxSOCKET_INPUT:
  310. wxLogError("Unexpected wxSOCKET_INPUT in wxSocketServer");
  311. break;
  312. case wxSOCKET_OUTPUT:
  313. wxLogError("Unexpected wxSOCKET_OUTPUT in wxSocketServer");
  314. break;
  315. case wxSOCKET_CONNECTION:
  316. {
  317. wxSocketBase* sock = m_listeningSocket->Accept();
  318. wxIPV4address addr;
  319. if (!sock->GetPeer(addr))
  320. {
  321. wxLogError("Server: cannot get peer info");
  322. } else {
  323. wxLogMessage("Got connection from %s:%d",addr.IPAddress().c_str(), addr.Service());
  324. }
  325. bool createThread;
  326. if (m_workMode != MIXED)
  327. createThread = m_workMode == THREADS;
  328. else
  329. createThread = (wxDateTime::Now().GetSecond())%2 == 0;
  330. if (createThread)
  331. {
  332. ThreadWorker* c = new ThreadWorker(sock);
  333. if (c->Create() == wxTHREAD_NO_ERROR)
  334. {
  335. m_threadWorkers.Append(c);
  336. if (m_threadWorkers.GetCount() > m_maxThreadWorkers)
  337. m_maxThreadWorkers++;
  338. m_threadWorkersCreated++;
  339. c->Run();
  340. }
  341. else
  342. {
  343. wxLogError("Server: cannot create next thread (current threads: %d", m_threadWorkers.size());
  344. };
  345. }
  346. else
  347. {
  348. EventWorker* w = new EventWorker(sock);
  349. m_eventWorkers.Append(w);
  350. if (m_eventWorkers.GetCount() > m_maxEventWorkers)
  351. m_maxEventWorkers++;
  352. m_eventWorkersCreated++;
  353. }
  354. }
  355. break;
  356. case wxSOCKET_LOST:
  357. wxLogError("Unexpected wxSOCKET_LOST in wxSocketServer");
  358. break;
  359. }
  360. }
  361. void Server::OnWorkerEvent(WorkerEvent& pEvent)
  362. {
  363. //wxLogMessage("Got worker event");
  364. for(TList::compatibility_iterator it = m_threadWorkers.GetFirst(); it ; it = it->GetNext())
  365. {
  366. if (it->GetData() == pEvent.m_sender)
  367. {
  368. wxLogVerbose("Deleting thread worker (%lu left)",
  369. static_cast<unsigned long>( m_threadWorkers.GetCount() ));
  370. it->GetData()->Wait();
  371. delete it->GetData();
  372. m_threadWorkers.DeleteNode(it);
  373. if (!pEvent.m_workerFailed)
  374. m_threadWorkersDone++;
  375. else
  376. m_threadWorkersFailed++;
  377. break;
  378. }
  379. }
  380. for(EList::compatibility_iterator it2 = m_eventWorkers.GetFirst(); it2 ; it2 = it2->GetNext())
  381. {
  382. if (it2->GetData() == pEvent.m_sender)
  383. {
  384. wxLogVerbose("Deleting event worker (%lu left)",
  385. static_cast<unsigned long>( m_eventWorkers.GetCount() ));
  386. delete it2->GetData();
  387. m_eventWorkers.DeleteNode(it2);
  388. if (!pEvent.m_workerFailed)
  389. m_eventWorkersDone++;
  390. else
  391. m_eventWorkersFailed++;
  392. break;
  393. }
  394. }
  395. if (m_eventWorkers.GetCount() == 0 && m_threadWorkers.GetCount() == 0)
  396. {
  397. mTimer.Start(1000,true);
  398. }
  399. }
  400. void Server::OnTimerEvent(wxTimerEvent&)
  401. {
  402. DumpStatistics();
  403. }
  404. wxBEGIN_EVENT_TABLE(Server,wxEvtHandler)
  405. EVT_SOCKET(wxID_ANY,Server::OnSocketEvent)
  406. EVT_WORKER(Server::OnWorkerEvent)
  407. EVT_TIMER(wxID_ANY,Server::OnTimerEvent)
  408. wxEND_EVENT_TABLE()
  409. ThreadWorker::ThreadWorker(wxSocketBase* pSocket) : wxThread(wxTHREAD_JOINABLE)
  410. {
  411. m_socket = pSocket;
  412. //Notify() cannot be called in thread context. We have to detach from main loop
  413. //before switching thread contexts.
  414. m_socket->Notify(false);
  415. m_socket->SetFlags(wxSOCKET_WAITALL|wxSOCKET_BLOCK);
  416. pSocket->GetPeer(m_peer);
  417. }
  418. wxThread::ExitCode ThreadWorker::Entry()
  419. {
  420. WorkerEvent e(this);
  421. if (!m_socket->IsConnected())
  422. {
  423. LogWorker("ThreadWorker: not connected",wxLOG_Error);
  424. return 0;
  425. }
  426. int to_process = -1;
  427. if (m_socket->IsConnected())
  428. {
  429. unsigned char signature[2];
  430. LogWorker("ThreadWorker: reading for data");
  431. to_process = 2;
  432. do
  433. {
  434. m_socket->Read(&signature,to_process);
  435. if (m_socket->Error())
  436. {
  437. LogWorker("ThreadWorker: Read error",wxLOG_Error);
  438. wxGetApp().AddPendingEvent(e);
  439. return 0;
  440. }
  441. to_process -= m_socket->LastCount();
  442. LogWorker(wxString::Format("to_process: %d",to_process));
  443. }
  444. while (!m_socket->Error() && to_process != 0);
  445. if (signature[0] == 0)
  446. {
  447. e.m_exit = true;
  448. return 0;
  449. }
  450. if (signature[0] == 0xCE)
  451. {
  452. LogWorker("This server does not support test2 from GUI client",wxLOG_Error);
  453. e.m_workerFailed = true;
  454. e.m_exit = true;
  455. return 0;
  456. }
  457. int size = signature[1] * (signature[0] == 0xBE ? 1 : 1024);
  458. char* buf = new char[size];
  459. LogWorker(wxString::Format("Message signature: chunks: %d, kilobytes: %d, size: %d (bytes)",signature[0],signature[1],size));
  460. to_process = size;
  461. LogWorker(wxString::Format("ThreadWorker: reading %d bytes of data",to_process));
  462. do
  463. {
  464. m_socket->Read(buf,to_process);
  465. if (m_socket->Error())
  466. {
  467. LogWorker("ThreadWorker: Read error",wxLOG_Error);
  468. wxGetApp().AddPendingEvent(e);
  469. return 0;
  470. }
  471. to_process -= m_socket->LastCount();
  472. LogWorker(wxString::Format("ThreadWorker: %d bytes readed, %d todo",m_socket->LastCount(),to_process));
  473. }
  474. while(!m_socket->Error() && to_process != 0);
  475. to_process = size;
  476. do
  477. {
  478. m_socket->Write(buf,to_process);
  479. if (m_socket->Error())
  480. {
  481. LogWorker("ThreadWorker: Write error",wxLOG_Error);
  482. break;
  483. }
  484. to_process -= m_socket->LastCount();
  485. LogWorker(wxString::Format("ThreadWorker: %d bytes written, %d todo",m_socket->LastCount(),to_process));
  486. }
  487. while(!m_socket->Error() && to_process != 0);
  488. }
  489. LogWorker("ThreadWorker: done");
  490. e.m_workerFailed = to_process != 0;
  491. m_socket->Destroy();
  492. wxGetApp().AddPendingEvent(e);
  493. return 0;
  494. }
  495. EventWorker::EventWorker(wxSocketBase* pSock)
  496. : m_socket(pSock),
  497. m_inbuf(NULL),
  498. m_infill(0),
  499. m_outbuf(NULL),
  500. m_outfill(0)
  501. {
  502. m_socket->SetNotify(wxSOCKET_LOST_FLAG|wxSOCKET_INPUT_FLAG|wxSOCKET_OUTPUT_FLAG);
  503. m_socket->Notify(true);
  504. m_socket->SetEventHandler(*this);
  505. m_socket->SetFlags(wxSOCKET_NOWAIT);
  506. m_socket->GetPeer(m_peer);
  507. }
  508. EventWorker::~EventWorker()
  509. {
  510. m_socket->Destroy();
  511. delete [] m_inbuf;
  512. delete [] m_outbuf;
  513. }
  514. void
  515. EventWorker::DoRead()
  516. {
  517. if (m_inbuf == NULL)
  518. {
  519. //read message header
  520. do
  521. {
  522. m_socket->Read(m_signature + m_infill, 2 - m_infill);
  523. if (m_socket->Error())
  524. {
  525. if (m_socket->LastError() != wxSOCKET_WOULDBLOCK)
  526. {
  527. LogWorker(wxString::Format("Read error (%d): %s",m_socket->LastError(),GetSocketErrorMsg(m_socket->LastError())),wxLOG_Error);
  528. m_socket->Close();
  529. }
  530. }
  531. else
  532. {
  533. m_infill += m_socket->LastCount();
  534. if (m_infill == 2)
  535. {
  536. unsigned char chunks = m_signature[1];
  537. unsigned char type = m_signature[0];
  538. if (type == 0xCE)
  539. {
  540. LogWorker("This server does not support test2 from GUI client",wxLOG_Error);
  541. m_written = -1; //wxSOCKET_LOST will interpret this as failure
  542. m_socket->Close();
  543. }
  544. else if (type == 0xBE || type == 0xDE)
  545. {
  546. m_size = chunks * (type == 0xBE ? 1 : 1024);
  547. m_inbuf = new char[m_size];
  548. m_outbuf = new char[m_size];
  549. m_infill = 0;
  550. m_outfill = 0;
  551. m_written = 0;
  552. LogWorker(wxString::Format("Message signature: len: %d, type: %s, size: %d (bytes)",chunks,type == 0xBE ? "b" : "kB",m_size));
  553. break;
  554. }
  555. else
  556. {
  557. LogWorker(wxString::Format("Unknown test type %x",type));
  558. m_socket->Close();
  559. }
  560. }
  561. }
  562. }
  563. while(!m_socket->Error() && (2 - m_infill != 0));
  564. }
  565. if (m_inbuf == NULL)
  566. return;
  567. //read message data
  568. do
  569. {
  570. if (m_size == m_infill)
  571. {
  572. m_signature[0] = m_signature[1] = 0x0;
  573. wxDELETEA(m_inbuf);
  574. m_infill = 0;
  575. return;
  576. }
  577. m_socket->Read(m_inbuf + m_infill,m_size - m_infill);
  578. if (m_socket->Error())
  579. {
  580. if (m_socket->LastError() != wxSOCKET_WOULDBLOCK)
  581. {
  582. LogWorker(wxString::Format("Read error (%d): %s",
  583. m_socket->LastError(),
  584. GetSocketErrorMsg(m_socket->LastError())),
  585. wxLOG_Error);
  586. m_socket->Close();
  587. }
  588. }
  589. else
  590. {
  591. memcpy(m_outbuf+m_outfill,m_inbuf+m_infill,m_socket->LastCount());
  592. m_infill += m_socket->LastCount();
  593. m_outfill += m_socket->LastCount();
  594. DoWrite();
  595. }
  596. }
  597. while(!m_socket->Error());
  598. };
  599. void EventWorker::OnSocketEvent(wxSocketEvent& pEvent)
  600. {
  601. switch(pEvent.GetSocketEvent())
  602. {
  603. case wxSOCKET_INPUT:
  604. DoRead();
  605. break;
  606. case wxSOCKET_OUTPUT:
  607. if ( m_outbuf )
  608. DoWrite();
  609. break;
  610. case wxSOCKET_CONNECTION:
  611. LogWorker("Unexpected wxSOCKET_CONNECTION in EventWorker", wxLOG_Error);
  612. break;
  613. case wxSOCKET_LOST:
  614. {
  615. LogWorker("Connection lost");
  616. WorkerEvent e(this);
  617. e.m_workerFailed = m_written != m_size;
  618. wxGetApp().AddPendingEvent(e);
  619. }
  620. break;
  621. }
  622. }
  623. void EventWorker::DoWrite()
  624. {
  625. do
  626. {
  627. if (m_written == m_size)
  628. {
  629. wxDELETEA(m_outbuf);
  630. m_outfill = 0;
  631. LogWorker( "All data written");
  632. return;
  633. }
  634. if (m_outfill - m_written == 0)
  635. {
  636. return;
  637. }
  638. m_socket->Write(m_outbuf + m_written,m_outfill - m_written);
  639. if (m_socket->Error())
  640. {
  641. if (m_socket->LastError() != wxSOCKET_WOULDBLOCK)
  642. {
  643. LogWorker(
  644. wxString::Format("Write error (%d): %s",
  645. m_socket->LastError(),
  646. GetSocketErrorMsg(m_socket->LastError())
  647. )
  648. ,wxLOG_Error
  649. );
  650. m_socket->Close();
  651. }
  652. else
  653. {
  654. LogWorker("Write would block, waiting for OUTPUT event");
  655. }
  656. }
  657. else
  658. {
  659. memmove(m_outbuf,m_outbuf+m_socket->LastCount(),m_outfill-m_socket->LastCount());
  660. m_written += m_socket->LastCount();
  661. }
  662. LogWorker(wxString::Format("Written %d of %d bytes, todo %d",
  663. m_socket->LastCount(),m_size,m_size - m_written));
  664. }
  665. while (!m_socket->Error());
  666. }
  667. wxBEGIN_EVENT_TABLE(EventWorker,wxEvtHandler)
  668. EVT_SOCKET(wxID_ANY,EventWorker::OnSocketEvent)
  669. wxEND_EVENT_TABLE()