summaryrefslogtreecommitdiffstats
path: root/tsconnectionthread.cpp
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2013-03-05 17:39:48 +0100
committermanuel <manuel@mausz.at>2013-03-05 17:39:48 +0100
commit310a2c101b32a5e71a616027b6a1b788a341bc02 (patch)
treea871e1dda8b1de141ae1400ba666fe3b1de96361 /tsconnectionthread.cpp
downloadtsclient-310a2c101b32a5e71a616027b6a1b788a341bc02.tar.gz
tsclient-310a2c101b32a5e71a616027b6a1b788a341bc02.tar.bz2
tsclient-310a2c101b32a5e71a616027b6a1b788a341bc02.zip
initial GPLv2 releaseHEADmaster
Diffstat (limited to 'tsconnectionthread.cpp')
-rw-r--r--tsconnectionthread.cpp728
1 files changed, 728 insertions, 0 deletions
diff --git a/tsconnectionthread.cpp b/tsconnectionthread.cpp
new file mode 100644
index 0000000..018afdf
--- /dev/null
+++ b/tsconnectionthread.cpp
@@ -0,0 +1,728 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; version 2 of the License.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
14 *
15 * Authors: Manuel Mausz (manuel@mausz.at)
16 * Christian Raschko (c.raschko@netcore.at)
17 */
18
19// Header
20#include "tsconnectionthread.h"
21#include "wxbufferex.h"
22
23//Libraries
24#include <wx/txtstrm.h>
25#include <wx/mstream.h>
26#include <wx/buffer.h>
27#include <wx/sckstrm.h>
28#include <wx/sstream.h>
29#include <wx/listimpl.cpp>
30
31WX_DEFINE_LIST(TSQueue);
32
33IMPLEMENT_CLASS(TSConnectionThread, wxObject)
34
35//------------------------------------------------------------------------------
36// Default CTor, Initializes the object
37TSConnectionThread::TSConnectionThread(TSClient *client, wxMutex *mutex)
38 : wxThread(wxTHREAD_JOINABLE)
39{
40 m_pMutex = mutex;
41
42 Create();
43 m_pClient = client;
44 m_ppCommands = new TSpCommandArray;
45 m_pMySock = new wxDatagramSocket(m_ClientAddr);
46 m_InQueue = new TSQueue;
47 m_OutQueue = new TSQueue;
48
49 m_Exit = false;
50 m_Error = false;
51 m_Timer = false;
52 m_pCurCmd = NULL;
53 m_LocalCmd = true;
54 m_Connected = false;
55 m_pMySock = NULL;
56
57 //register known commands
58 RegisterCommand(new TSCmdSendLogin);
59 RegisterCommand(new TSCmdRecvServer);
60 RegisterCommand(new TSCmdSendDefault);
61 RegisterCommand(new TSCmdRecvChannel);
62 RegisterCommand(new TSCmdRecvUser);
63 RegisterCommand(new TSCmdRecvAck);
64 RegisterCommand(new TSCmdSendAck);
65 RegisterCommand(new TSCmdRecvUrl);
66 RegisterCommand(new TSCmdSendPing);
67 RegisterCommand(new TSCmdRecvPing);
68 RegisterCommand(new TSCmdSendLogout);
69 RegisterCommand(new TSCmdRecvLogout);
70 RegisterCommand(new TSCmdRecvAddPlayer);
71 RegisterCommand(new TSCmdRecvPlayerFlags);
72 RegisterCommand(new TSCmdRecvAddChannel);
73 RegisterCommand(new TSCmdRecvMovePlayer);
74 RegisterCommand(new TSCmdRecvMovePlayer2);
75 RegisterCommand(new TSCmdRecvDelChannel);
76 RegisterCommand(new TSCmdRecvServerUpdate);
77 RegisterCommand(new TSCmdSendAddChannel);
78 RegisterCommand(new TSCmdSendDelChannel);
79 RegisterCommand(new TSCmdSendMovePlayer);
80 RegisterCommand(new TSCmdSendSetChannelPassword);
81 RegisterCommand(new TSCmdSendSetChannelName);
82 RegisterCommand(new TSCmdSendSetChannelTopic);
83 RegisterCommand(new TSCmdSendSetChannelDescription);
84 RegisterCommand(new TSCmdSendSetChannelMaxPlayers);
85 RegisterCommand(new TSCmdSendSetChannelFlagsCodec);
86 RegisterCommand(new TSCmdSendSetChannelOrder);
87 RegisterCommand(new TSCmdRecvSetChannelName);
88 RegisterCommand(new TSCmdRecvSetChannelTopic);
89 RegisterCommand(new TSCmdRecvSetChannelDescription);
90 RegisterCommand(new TSCmdRecvSetChannelMaxPlayers);
91 RegisterCommand(new TSCmdRecvSetChannelFlagsCodec);
92 RegisterCommand(new TSCmdRecvSetChannelOrder);
93 RegisterCommand(new TSCmdSendKickPlayer);
94 RegisterCommand(new TSCmdRecvChannelPasswordChanged);
95
96 //for all unknown commands
97 RegisterCommand(new TSCmdRecvUnknown);
98}
99
100//------------------------------------------------------------------------------
101//Default DTor
102TSConnectionThread::~TSConnectionThread()
103{
104 /* DON'T USE THIS */
105}
106
107//------------------------------------------------------------------------------
108// thread execution starts here
109wxThread::ExitCode TSConnectionThread::Entry()
110{
111 wxLogMessage(_T("TSConnection: thread started."));
112
113 m_ClientAddr.AnyAddress();
114 m_ClientAddr.Service(0);
115
116 m_ServerAddr.Hostname(m_pClient->GetServer()->GetServerAddress());
117 m_ServerAddr.Service(m_pClient->GetServer()->GetPort());
118
119 //no methode to reset socket
120 if (m_pMySock)
121 {
122 wxASSERT(m_pMySock != NULL);
123 m_pMySock->Destroy();
124 m_pMySock = NULL;
125 }
126
127 m_pMySock = new wxDatagramSocket(m_ClientAddr);
128 if(m_pMySock->Error())
129 {
130 wxLogError(_T("creating socket, terminating thread."));
131 return wxThread::ExitCode(EXIT_FAILURE);
132 }
133
134 m_pMySock->SetTimeout(SOCKET_TIMEOUT);
135
136 //empty dgram to initialize and remember peer
137 //allows us to use wxSocketOutputStream afterwards
138 m_pMySock->SendTo(m_ServerAddr, NULL, 0);
139
140 if(!MainLoop())
141 {
142 wxLogDebug(_T("Error: %s"), GetLastError().c_str());
143 return wxThread::ExitCode(EXIT_FAILURE);
144 }
145
146 return wxThread::ExitCode(EXIT_SUCCESS);
147}
148
149//------------------------------------------------------------------------------
150// and stops here
151void TSConnectionThread::OnExit()
152{
153 wxLogDebug(_T("TSConnection: thread terminated."));
154
155 //do the necessary cleanup
156 for(size_t i = 0; i < m_ppCommands->GetCount(); i++)
157 delete m_ppCommands->Item(i);
158
159 m_InQueue->DeleteContents(true);
160 m_OutQueue->DeleteContents(true);
161
162 wxASSERT(m_InQueue != NULL);
163 delete m_InQueue;
164 m_InQueue = NULL;
165
166 wxASSERT(m_OutQueue != NULL);
167 delete m_OutQueue;
168 m_OutQueue = NULL;
169
170 wxASSERT(m_ppCommands != NULL);
171 delete m_ppCommands;
172 m_ppCommands = NULL;
173
174 wxASSERT(m_pMySock != NULL);
175 m_pMySock->Destroy();
176 m_pMySock = NULL;
177
178 if(m_pCurCmd != NULL)
179 {
180 delete m_pCurCmd;
181 m_pCurCmd = NULL;
182 }
183}
184
185//------------------------------------------------------------------------------
186// SyncSendCmdError
187bool TSConnectionThread::SyncSendCmdLastError()
188{
189 //wxLogDebug(_T("SyncSendCmdLastError"));
190 m_LocalCmd = true;
191
192 m_SWTimeout.Start();
193 m_SWTimeout.Pause();
194
195 TSCmd *cmd = m_pClient->GetSync();
196 cmd->error = true;
197 cmd->lasterror = m_LastError;
198 cmd->executed = true;
199 m_pClient->m_Lock = false;
200 return true;
201}
202
203//------------------------------------------------------------------------------
204// Sync with TSClient and send command
205bool TSConnectionThread::SyncSendCmd()
206{
207 //wxLogDebug(_T("SyncSendCmd"));
208 TSCmd *cmd = m_pClient->GetSync();
209 m_pCurCmd = cmd;
210
211 if(cmd->id == 0)
212 {
213 SetLastError(_T("no command id"));
214 SyncSendCmdLastError();
215 return true;
216 }
217
218 if(cmd->id != TS_CMD_SEND_LOGIN &&
219 cmd->id != TS_CMD_SEND_DEFAULT &&
220 !m_Connected)
221 {
222 SetLastError(_T("no connection to server"));
223 SyncSendCmdLastError();
224 return true;
225 }
226
227 m_LocalCmd = false;
228 SendCommand(cmd);
229
230 return true;
231}
232
233//------------------------------------------------------------------------------
234// Register a Command, the class takes care of this pointer.
235void TSConnectionThread::RegisterCommand(TSCommand *cmd)
236{
237 wxASSERT(cmd != NULL);
238 m_ppCommands->Add(cmd);
239}
240
241//------------------------------------------------------------------------------
242// Executes a command.
243bool TSConnectionThread::ExecuteCommand(wxInputStream &istrm,
244 wxOutputStream &ostrm,
245 TSCmd *cmd)
246{
247 wxLogDebug(_T("ExecuteCommand: 0x%X"), cmd->id);
248 for(size_t i = 0; i < m_ppCommands->GetCount(); i++)
249 {
250 if(m_ppCommands->Item(i)->IsCommand(cmd->id))
251 {
252 if(m_ppCommands->Item(i)->ProcessCommand(istrm, ostrm, cmd))
253 return true;
254 else
255 {
256 SetLastError(m_ppCommands->Item(i)->GetLastError());
257 return false;
258 }
259 }
260 }
261
262 #ifdef IGNORE_UNKNOWN_COMMANDS
263 //used for unknown commands
264 cmd->id = TS_CMD_RECV_UNKNOWN;
265 return ExecuteCommand(istrm, ostrm, cmd);
266 #else
267 SetLastError(_T("invalid command"));
268 return false;
269 #endif
270}
271
272//------------------------------------------------------------------------------
273// Dumps object.
274void TSConnectionThread::Dump(wxOutputStream &ostrm) const
275{
276 wxTextOutputStream out(ostrm);
277 out << _T("Object: TSConnection (") << wxString::Format(_T("0x%X"), this) << _T(")") << endl;
278 out << _T("-wxString m_LastError: ") << m_LastError << endl;
279}
280
281//------------------------------------------------------------------------------
282// send command.
283bool TSConnectionThread::SendOutputCommand(TSCmd *cmd)
284{
285 //wxLogDebug(_T("SendOutputCommand: 0x%X"), cmd->id);
286 if(!SendCommandToSocket(cmd))
287 return false;
288
289 /* this m_pCurCmd code possibly contains a memleak
290 * the lines below solves ~95% of them
291 */
292 /*if(m_pCurCmd != NULL)
293 {
294 delete m_pCurCmd;
295 m_pCurCmd = NULL;
296 }*/
297
298 switch(cmd->id)
299 {
300 case TS_CMD_SEND_LOGIN:
301 AddInputCommand(new TSCmd(TS_CMD_RECV_SERVER, cmd));
302 m_pCurCmd = new TSCmd(TS_CMD_RECV_SERVER, cmd);
303 break;
304 case TS_CMD_SEND_DEFAULT:
305 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
306 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
307 break;
308 case TS_CMD_SEND_PING:
309 AddInputCommand(new TSCmd(TS_CMD_RECV_PING, cmd));
310 m_pCurCmd = new TSCmd(TS_CMD_RECV_PING, cmd);
311 break;
312 case TS_CMD_SEND_LOGOUT:
313 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
314 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
315 break;
316 case TS_CMD_SEND_ADD_CHANNEL:
317 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
318 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
319 break;
320 case TS_CMD_SEND_DEL_CHANNEL:
321 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
322 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
323 break;
324 case TS_CMD_SEND_MOVE_PLAYER:
325 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
326 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
327 break;
328 case TS_CMD_SEND_SET_CHANNEL_PASSWORD:
329 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
330 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
331 break;
332 case TS_CMD_SEND_SET_CHANNEL_NAME:
333 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
334 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
335 break;
336 case TS_CMD_SEND_SET_CHANNEL_TOPIC:
337 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
338 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
339 break;
340 case TS_CMD_SEND_SET_CHANNEL_DESCRIPTION:
341 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
342 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
343 break;
344 case TS_CMD_SEND_SET_CHANNEL_MAXPLAYERS:
345 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
346 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
347 break;
348 case TS_CMD_SEND_SET_CHANNEL_FLAGSCODEC:
349 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
350 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
351 break;
352 case TS_CMD_SEND_SET_CHANNEL_ORDER:
353 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
354 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
355 break;
356 case TS_CMD_SEND_KICK_PLAYER:
357 AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd));
358 m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd);
359 break;
360 case TS_CMD_SEND_ACK:
361 break;
362 }
363
364 return true;
365}
366
367//------------------------------------------------------------------------------
368// SendQueuedCommand.
369bool TSConnectionThread::SendQueuedCommand()
370{
371 //wxLogDebug(_T("SendQueuedCommand"));
372 wxTSQueueNode *node = m_OutQueue->GetFirst();
373 TSCmd *t = node->GetData();
374 if(!SendOutputCommand(t))
375 return false;
376
377 delete t;
378 if(!m_OutQueue->DeleteNode(node))
379 {
380 SetLastError(_T("deleting node"));
381 return false;
382 }
383
384 return true;
385}
386
387//------------------------------------------------------------------------------
388// Send command.
389bool TSConnectionThread::SendCommand(TSCmd *cmd)
390{
391 //wxLogDebug(_T("SendCommand: 0x%X"), cmd->id);
392 if(m_pCurCmd == NULL)
393 m_pCurCmd = cmd;
394
395 m_SWTimeout.Start();
396
397 if(!SendOutputCommand(cmd))
398 return false;
399 m_Retries = 0;
400 return true;
401}
402
403//------------------------------------------------------------------------------
404// Send command to socket.
405bool TSConnectionThread::SendCommandToSocket(TSCmd *cmd)
406{
407 //wxLogDebug(_T("SendCommandToSocket: 0x%X"), cmd->id);
408 wxLogVerbose(_T("TSClient: command %#x sent"),cmd->id);
409
410 wxSocketOutputStream so(*m_pMySock);
411 wxBufferedOutputStream out(so);
412 wxSocketInputStream si(*m_pMySock);
413 wxBufferedInputStream in(si);
414
415 if(!ExecuteCommand(in, out, cmd))
416 {
417 SetLastError(_T("execute command"));
418 return false;
419 }
420
421 out.Sync();
422 return true;
423}
424
425//------------------------------------------------------------------------------
426// Add command.
427void TSConnectionThread::AddOutputCommand(TSCmd *cmd)
428{
429 //wxLogDebug(_T("AddOutputCommand: 0x%X"), cmd->id);
430 m_OutQueue->Append(cmd);
431}
432
433//------------------------------------------------------------------------------
434// CheckInputQueue
435bool TSConnectionThread::CheckInputQueue(TSCmd *cmd)
436{
437 wxLogDebug(_T("CheckInputQueue: 0x%X, 0x%X"), cmd->id, cmd->pktid);
438
439 switch(cmd->id)
440 {
441 case TS_CMD_RECV_CHANNEL:
442 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
443 break;
444 case TS_CMD_RECV_USER:
445 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
446 break;
447 case TS_CMD_RECV_URL:
448 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
449 wxLogVerbose(_T("TSClient: connected"));
450 m_Connected = true;
451 m_Timer = true;
452 break;
453 case TS_CMD_RECV_LOGOUT:
454 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
455 break;
456 case TS_CMD_RECV_UNKNOWN:
457 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
458 break;
459 case TS_CMD_RECV_ACK:
460 break;
461 case TS_CMD_RECV_SERVER:
462 //AddOutputCommand(new TSCmd(TS_CMD_SEND_DEFAULT, cmd));
463 break;
464 case TS_CMD_RECV_ADD_PLAYER:
465 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
466 break;
467 case TS_CMD_RECV_PLAYER_FLAGS:
468 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
469 break;
470 case TS_CMD_RECV_ADD_CHANNEL:
471 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
472 break;
473 case TS_CMD_RECV_MOVE_PLAYER:
474 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
475 break;
476 case TS_CMD_RECV_MOVE_PLAYER2:
477 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
478 break;
479 case TS_CMD_RECV_DEL_CHANNEL:
480 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
481 break;
482 case TS_CMD_RECV_SERVER_UPDATE:
483 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
484 // force reconnect for the sake of consistency
485 AddOutputCommand(new TSCmd(TS_CMD_SEND_LOGOUT, cmd));
486 break;
487 case TS_CMD_RECV_SET_CHANNEL_NAME:
488 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
489 break;
490 case TS_CMD_RECV_SET_CHANNEL_TOPIC:
491 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
492 break;
493 case TS_CMD_RECV_SET_CHANNEL_DESCRIPTION:
494 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
495 break;
496 case TS_CMD_RECV_SET_CHANNEL_MAXPLAYERS:
497 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
498 break;
499 case TS_CMD_RECV_SET_CHANNEL_FLAGSCODEC:
500 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
501 break;
502 case TS_CMD_RECV_SET_CHANNEL_ORDER:
503 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
504 break;
505 case TS_CMD_RECV_CHANNEL_PASSWORD_CHANGED:
506 AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd));
507 break;
508 case TS_CMD_RECV_PING:
509 break;
510 default:
511 wxLogWarning(_T("input queue: invalid command %#x, ignoring"), cmd->id);
512 break;
513 }
514
515 for(wxTSQueueNode *node = m_InQueue->GetFirst(); node != NULL; node = node->GetNext())
516 {
517 TSCmd *cur = node->GetData();
518 //cmd found
519 if(cur->id == cmd->id)
520 {
521 delete cur;
522 if(!m_InQueue->DeleteNode(node))
523 {
524 SetLastError(_T("deleting node"));
525 return false;
526 }
527 //return true;
528 }
529
530 if(m_pCurCmd->id == cmd->id)
531 {
532 m_pMutex->Lock();
533
534 wxLogDebug(_T("found in queue: 0x%X"), cmd->id);
535 delete m_pCurCmd;
536 m_pCurCmd = NULL;
537 if (!m_LocalCmd)
538 {
539 m_pClient->m_Lock = false;
540 m_pClient->GetSync()->executed = true;
541 }
542 m_LocalCmd = true;
543
544 m_SWTimeout.Pause();
545
546 m_pMutex->Unlock();
547
548 return true;
549 }
550 }
551
552 return true;
553}
554
555//------------------------------------------------------------------------------
556// ReadQueuedCommand.
557bool TSConnectionThread::RecvCommand()
558{
559 wxSocketOutputStream so(*m_pMySock);
560 wxMemoryBufferEx buf(1024);
561 m_pMySock->RecvFrom(m_ServerAddr, buf.GetData(), 1024);
562 buf.SetDataLen(m_pMySock->LastCount());
563 wxMemoryInputStream in(buf.GetData(), buf.GetDataLen());
564 wxDataInputStream data(in);
565
566 TSCmd cmd;
567 cmd.id = data.Read32(); //read id
568 data.Read32(); //Session id
569 data.Read32(); //Player id
570 cmd.pktid = data.Read32(); //Packet count
571 cmd.client = m_pClient;
572 in.SeekI(0);
573
574 wxLogVerbose(_T("TSClient: command %#x received"), cmd.id);
575
576 // dirty workaround for crappy teamspeak protocol, which splits off pakets
577 if(cmd.id == TS_CMD_RECV_CHANNEL)
578 {
579 in.SeekI(-1, wxFromEnd);
580 if(data.Read8() != 0)
581 {
582 wxMemoryBuffer buf_b2(1024);
583 m_pMySock->RecvFrom(m_ServerAddr, buf_b2.GetData(), 1024);
584 buf_b2.SetDataLen(m_pMySock->LastCount());
585 wxMemoryInputStream in_b2(buf_b2.GetData(), buf_b2.GetDataLen());
586 wxDataInputStream data_b2(in_b2);
587
588 if(data_b2.Read32() != cmd.id)
589 {
590 SetLastError(_T("invalid command, perhaps wrong paket order (udp?)"));
591 return false;
592 }
593
594 data_b2.Read32(); //Session id
595 data_b2.Read32(); //Player id
596 cmd.pktid = data_b2.Read32(); //Packet count
597 data_b2.Read32(); //read unknown
598 data_b2.Read32(); //CRC
599
600 // send acknowledge for 2nd packet
601 if(!CheckInputQueue(&cmd))
602 return false;
603
604 // append bytes
605 while(!in_b2.Eof())
606 buf.AppendByte(in_b2.GetC());
607 }
608 in.SeekI(0);
609 }
610
611 // update streams (dirty, but copy-operator is private)
612 wxMemoryInputStream in2(buf.GetData(), buf.GetDataLen());
613 wxDataInputStream data2(in2);
614 if(!ExecuteCommand(in2, so, &cmd))
615 {
616 switch(cmd.id)
617 {
618 case TS_CMD_RECV_SERVER:
619 SyncSendCmdLastError();
620 break;
621 }
622
623 return false;
624 }
625 if(!CheckInputQueue(&cmd))
626 return false;
627
628 return true;
629}
630
631//------------------------------------------------------------------------------
632// Add command.
633void TSConnectionThread::AddInputCommand(TSCmd *cmd)
634{
635 //wxLogDebug(_T("AddInputCommand: 0x%X"), cmd->id);
636 m_InQueue->Append(cmd);
637}
638
639//------------------------------------------------------------------------------
640// StartMainLoop
641bool TSConnectionThread::MainLoop()
642{
643 wxStopWatch sw;
644 sw.Start();
645 m_Retries = 0;
646
647 while(1)
648 {
649 //Is new command available
650 m_pMutex->Lock();
651 if((m_pClient->GetSync() != NULL) &&
652 (m_pCurCmd == NULL) &&
653 (m_pClient->m_Lock) &&
654 (m_OutQueue->GetCount() == 0))
655 {
656 m_SWTimeout.Start();
657 SyncSendCmd();
658 }
659 m_pMutex->Unlock();
660
661 //Is some data in queue
662 if(m_OutQueue->GetCount() != 0)
663 {
664 if(!SendQueuedCommand())
665 return false;
666 }
667
668 //Is new data available
669 if(m_pMySock->IsData())
670 {
671 if(!RecvCommand())
672 return false;
673 }
674
675 //Send ping
676 if((sw.Time() >= PING_INTERMITTENT) && m_Timer)
677 {
678 sw.Start();
679 TSCmd tmp;
680 tmp.client = m_pClient;
681 if(m_pCurCmd == NULL)
682 SendCommand(new TSCmd(TS_CMD_SEND_PING, &tmp));
683 }
684
685 //Check for timeout
686 if(m_SWTimeout.Time() > CMD_TIMEOUT)
687 {
688 SetLastError(_T("command timeout"));
689
690 m_pCurCmd = NULL;
691
692 if(!m_LocalCmd)
693 {
694 SyncSendCmdLastError();
695 }
696
697 m_LocalCmd = true;
698 //reset timer
699 m_SWTimeout.Start();
700 m_SWTimeout.Pause();
701
702 wxLogVerbose(_T("TSClient: disconnected"));
703 m_Connected = false;
704 /*
705 if(++m_Retries <= MAX_RETRIES)
706 {
707 m_Connected = false;
708 }
709 */
710 return false;
711 }
712
713 //Check if we should delete our self
714 if(TestDestroy())
715 return true;
716
717 //If an error occurred, end thread
718 if(m_Error)
719 return false;
720
721 //If m_Exit is set, end thread
722 if(m_Exit)
723 return true;
724
725 Sleep(10);
726 }
727}
728