1 /******************************************************************************\
2  * Copyright (c) 2004-2020
3  *
4  * Author(s):
5  *  Volker Fischer
6  *
7  ******************************************************************************
8  *
9  * This program is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU General Public License as published by the Free Software
11  * Foundation; either version 2 of the License, or (at your option) any later
12  * version.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
22  *
23 \******************************************************************************/
24 
25 /*
26 Protocol message definition
27 ---------------------------
28 
29 - All messages received need to be acknowledged by an acknowledge packet (except
30   of connection less messages)
31 
32 
33 
34 MAIN FRAME
35 ----------
36 
37     +-------------+------------+------------+------------------+ ...
38     | 2 bytes TAG | 2 bytes ID | 1 byte cnt | 2 bytes length n | ...
39     +-------------+------------+------------+------------------+ ...
40         ... --------------+-------------+
41         ...  n bytes data | 2 bytes CRC |
42         ... --------------+-------------+
43 
44 - TAG is an all zero bit word to identify protocol messages
45 - message ID defined by the defines PROTMESSID_x
46 - cnt: counter which is increment for each message and wraps around at 255
47 - length n in bytes of the data
48 - actual data, dependent on message type
49 - 16 bits CRC, calculated over the entire message and is transmitted inverted
50   Generator polynom: G_16(x) = x^16 + x^12 + x^5 + 1, initial state: all ones
51 
52 
53 
54 SPLIT MESSAGE CONTAINER
55 -----------------------
56 
57     +------------+------------------------+------------------+--------------+
58     | 2 bytes ID | 1 byte number of parts | 1 byte split cnt | n bytes data |
59     +------------+------------------------+------------------+--------------+
60 
61 - ID is the message ID of the message being split
62 - number of parts - total number of parts comprising the whole message
63 - split cnt - number within number total for this part of the message
64 - data - subset of the data part of the original message being split
65 
66 
67 
68 MESSAGES (with connection)
69 --------------------------
70 
71 - PROTMESSID_ACKN: Acknowledgement message
72 
73     +------------------------------------------+
74     | 2 bytes ID of message to be acknowledged |
75     +------------------------------------------+
76 
77     note: the cnt value is the same as of the message to be acknowledged
78 
79 
80 - PROTMESSID_JITT_BUF_SIZE: Jitter buffer size
81 
82     +--------------------------+
83     | 2 bytes number of blocks |
84     +--------------------------+
85 
86 
87 - PROTMESSID_REQ_JITT_BUF_SIZE: Request jitter buffer size
88 
89     note: does not have any data -> n = 0
90 
91 
92 - PROTMESSID_CLIENT_ID: Sends the current client ID to the client
93 
94     +---------------------------------+
95     | 1 byte channel ID of the client |
96     +---------------------------------+
97 
98 
99 - PROTMESSID_CHANNEL_GAIN: Gain of channel
100 
101     +-------------------+--------------+
102     | 1 byte channel ID | 2 bytes gain |
103     +-------------------+--------------+
104 
105 
106 - PROTMESSID_CHANNEL_PAN: Gain of channel
107 
108     +-------------------+-----------------+
109     | 1 byte channel ID | 2 bytes panning |
110     +-------------------+-----------------+
111 
112 
113 - PROTMESSID_MUTE_STATE_CHANGED: Mute state of your signal at another client has changed
114 
115     +-------------------+-----------------+
116     | 1 byte channel ID | 1 byte is muted |
117     +-------------------+-----------------+
118 
119 
120 - PROTMESSID_CONN_CLIENTS_LIST: Information about connected clients
121 
122     for each connected client append following data:
123 
124     +-------------------+-----------------+--------------------+ ...
125     | 1 byte channel ID | 2 bytes country | 4 bytes instrument | ...
126     +-------------------+-----------------+--------------------+ ...
127         ... --------------------+--------------------------------------+ ...
128         ...  1 byte skill level | 4 bytes zero (used to be IP address) | ...
129         ... --------------------+--------------------------------------+ ...
130         ... ------------------+---------------------------+
131         ...  2 bytes number n | n bytes UTF-8 string name |
132         ... ------------------+---------------------------+
133         ... ------------------+---------------------------+
134         ...  2 bytes number n | n bytes UTF-8 string city |
135         ... ------------------+---------------------------+
136 
137 
138 - PROTMESSID_REQ_CONN_CLIENTS_LIST: Request connected clients list
139 
140     note: does not have any data -> n = 0
141 
142 
143 - PROTMESSID_CHANNEL_INFOS: Information about the channel
144 
145     +-----------------+--------------------+ ...
146     | 2 bytes country | 4 bytes instrument | ...
147     +-----------------+--------------------+ ...
148         ... --------------------+ ...
149         ...  1 byte skill level | ...
150         ... --------------------+ ...
151         ... ------------------+---------------------------+ ...
152         ...  2 bytes number n | n bytes UTF-8 string name | ...
153         ... ------------------+---------------------------+ ...
154         ... ------------------+---------------------------+
155         ...  2 bytes number n | n bytes UTF-8 string city |
156         ... ------------------+---------------------------+
157 
158 
159 - PROTMESSID_REQ_CHANNEL_INFOS: Request infos of the channel
160 
161     note: does not have any data -> n = 0
162 
163 
164 - PROTMESSID_CHAT_TEXT: Chat text
165 
166     +------------------+----------------------+
167     | 2 bytes number n | n bytes UTF-8 string |
168     +------------------+----------------------+
169 
170     - "UTF-8 string": the chat message (plain text from client to server;
171       HTML from server to client)
172 
173 
174 - PROTMESSID_NETW_TRANSPORT_PROPS: Properties for network transport
175 
176     +------------------------+-------------------------+-----------------+ ...
177     | 4 bytes base netw size | 2 bytes block size fact | 1 byte num chan | ...
178     +------------------------+-------------------------+-----------------+ ...
179         ... ------------------+-----------------------+ ...
180         ...  4 bytes sam rate | 2 bytes audiocod type | ...
181         ... ------------------+-----------------------+ ...
182         ... ---------------+----------------------+
183         ...  2 bytes flags | 4 bytes audiocod arg |
184         ... ---------------+----------------------+
185 
186     - "base netw size":  length of the base network packet (frame) in bytes
187     - "block size fact": block size factor
188     - "num chan":        number of channels of the audio signal, e.g. "2" is
189                          stereo
190     - "sam rate":        sample rate of the audio stream
191     - "audiocod type":   audio coding type, the following types are supported:
192                           - 0: none, no audio coding applied
193                           - 1: CELT
194                           - 2: OPUS
195                           - 3: OPUS64
196     - "flags":           flags indicating network properties:
197                           - 0: none
198                           - 1: WITH_COUNTER (a packet counter is added to the audio packet)
199     - "audiocod arg":    argument for the audio coder, if not used this value
200                          shall be set to 0
201 
202 
203 - PROTMESSID_REQ_NETW_TRANSPORT_PROPS: Request properties for network transport
204 
205     note: does not have any data -> n = 0
206 
207 
208 - PROTMESSID_REQ_SPLIT_MESS_SUPPORT: Request split message support
209 
210     note: does not have any data -> n = 0
211 
212 
213 - PROTMESSID_SPLIT_MESS_SUPPORTED: Split messages are supported
214 
215     note: does not have any data -> n = 0
216 
217 
218 - PROTMESSID_LICENCE_REQUIRED: Licence required to connect to the server
219 
220     +---------------------+
221     | 1 byte licence type |
222     +---------------------+
223 
224 
225 - PROTMESSID_VERSION_AND_OS: Version number and operating system
226 
227     +-------------------------+------------------+------------------------------+
228     | 1 byte operating system | 2 bytes number n | n bytes UTF-8 string version |
229     +-------------------------+------------------+------------------------------+
230 
231 
232 // #### COMPATIBILITY OLD VERSION, TO BE REMOVED ####
233 - PROTMESSID_OPUS_SUPPORTED: Informs that OPUS codec is supported
234 
235     note: does not have any data -> n = 0
236 
237 
238 - PROTMESSID_RECORDER_STATE: notifies of changes in the server jam recorder state
239 
240     +--------------+
241     | 1 byte state |
242     +--------------+
243 
244     state is a value from the enum ERecorderState:
245     - 0 undefined (not used by protocol messages)
246     - tbc
247 
248 
249 CONNECTION LESS MESSAGES
250 ------------------------
251 
252 - PROTMESSID_CLM_PING_MS: Connection less ping message (for measuring the ping
253                           time)
254 
255     +-----------------------------+
256     | 4 bytes transmit time in ms |
257     +-----------------------------+
258 
259 
260 - PROTMESSID_CLM_PING_MS_WITHNUMCLIENTS: Connection less ping message (for
261                                          measuring the ping time) with the
262                                          info about the current number of
263                                          connected clients
264 
265     +-----------------------------+---------------------------------+
266     | 4 bytes transmit time in ms | 1 byte number connected clients |
267     +-----------------------------+---------------------------------+
268 
269 
270 - PROTMESSID_CLM_SERVER_FULL: Connection less server full message
271 
272     note: does not have any data -> n = 0
273 
274 
275 - PROTMESSID_CLM_REGISTER_SERVER: Register a server, providing server
276                                   information
277 
278     +------------------------------+ ...
279     | 2 bytes server internal port | ...
280     +------------------------------+ ...
281         ... -----------------+----------------------------------+ ...
282         ...  2 bytes country | 1 byte maximum connected clients | ...
283         ... -----------------+----------------------------------+ ...
284         ... ---------------------+ ...
285         ...  1 byte is permanent | ...
286         ... ---------------------+ ...
287         ... ------------------+----------------------------------+ ...
288         ...  2 bytes number n | n bytes UTF-8 string server name | ...
289         ... ------------------+----------------------------------+ ...
290         ... ------------------+----------------------------------------------+ ...
291         ...  2 bytes number n | n bytes UTF-8 string server internal address | ...
292         ... ------------------+----------------------------------------------+ ...
293         ... ------------------+---------------------------+
294         ...  2 bytes number n | n bytes UTF-8 string city |
295         ... ------------------+---------------------------+
296 
297     - "country" is according to "Common Locale Data Repository" which is used in
298       the QLocale class
299     - "maximum connected clients" is the maximum number of clients which can
300       be connected to the server at the same time
301     - "is permanent" is a flag which indicates if the server is permanent
302       online or not. If this value is any value <> 0 indicates that the server
303       is permanent online.
304     - "server internal address" represents the IPv4 address as a dotted quad to
305       be used by clients with the same external IP address as the server.
306       NOTE: In the PROTMESSID_CLM_SERVER_LIST list, this field will be empty
307       as only the initial IP address should be used by the client.  Where
308       necessary, that value will contain the server internal address.
309       When running a directory server and a slave server behind the same NAT,
310       this field is used the other way round: It will contain the public
311       IP in this case which will be served to clients from the Internet.
312 
313 
314 - PROTMESSID_CLM_REGISTER_SERVER_EX: Register a server, providing extended server
315                                      information
316 
317     +--------------------------------+-------------------------------+
318     | PROTMESSID_CLM_REGISTER_SERVER | PROTMESSID_CLM_VERSION_AND_OS |
319     +--------------------------------+-------------------------------+
320 
321 
322 - PROTMESSID_CLM_UNREGISTER_SERVER: Unregister a server
323 
324     note: does not have any data -> n = 0
325 
326 
327 - PROTMESSID_CLM_SERVER_LIST: Server list message
328 
329     for each registered server append following data:
330 
331     +--------------------+--------------------------------+
332     | 4 bytes IP address | PROTMESSID_CLM_REGISTER_SERVER |
333     +--------------------+--------------------------------+
334 
335     - "PROTMESSID_CLM_REGISTER_SERVER" means that exactly the same message body
336       of the PROTMESSID_CLM_REGISTER_SERVER message is used
337 
338 
339 - PROTMESSID_CLM_RED_SERVER_LIST: Reduced server list message (to have less UDP fragmentation)
340 
341     for each registered server append following data:
342 
343     +--------------------+------------------------------+ ...
344     | 4 bytes IP address | 2 bytes server internal port | ...
345     +--------------------+------------------------------+ ...
346         ... -----------------+----------------------------------+
347         ...  1 byte number n | n bytes UTF-8 string server name |
348         ... -----------------+----------------------------------+
349 
350 
351 - PROTMESSID_CLM_REQ_SERVER_LIST: Request server list
352 
353     note: does not have any data -> n = 0
354 
355 
356 - PROTMESSID_CLM_SEND_EMPTY_MESSAGE: Send "empty message" message
357 
358     +--------------------+--------------+
359     | 4 bytes IP address | 2 bytes port |
360     +--------------------+--------------+
361 
362 
363 - PROTMESSID_CLM_DISCONNECTION: Disconnect message
364 
365     note: does not have any data -> n = 0
366 
367 
368 - PROTMESSID_CLM_VERSION_AND_OS: Version number and operating system
369 
370     +-------------------------+------------------+------------------------------+
371     | 1 byte operating system | 2 bytes number n | n bytes UTF-8 string version |
372     +-------------------------+------------------+------------------------------+
373 
374 
375 - PROTMESSID_CLM_REQ_VERSION_AND_OS: Request version number and operating system
376 
377     note: does not have any data -> n = 0
378 
379 
380 - PROTMESSID_CLM_CONN_CLIENTS_LIST: Information about connected clients
381 
382     for each connected client append the PROTMESSID_CONN_CLIENTS_LIST:
383 
384     +------------------------------+------------------------------+ ...
385     | PROTMESSID_CONN_CLIENTS_LIST | PROTMESSID_CONN_CLIENTS_LIST | ...
386     +------------------------------+------------------------------+ ...
387 
388 
389 - PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST: Request the connected clients list
390 
391     note: does not have any data -> n = 0
392 
393 
394 - PROTMESSID_CLM_CHANNEL_LEVEL_LIST: The channel level list
395 
396     +----------------------------------+
397     | ( ( n + 1 ) / 2 ) * 4 bit values |
398     +----------------------------------+
399 
400     n is number of connected clients
401 
402     the values are the maximum channel levels for a client frame converted
403     to the range of CLevelMeter in 4 bits, two entries per byte
404     with the earlier channel in the lower half of the byte
405 
406     where an odd number of clients is connected, there will be four unused
407     upper bits in the final byte, containing 0xF (which is out of range)
408 
409     the server may compute the message when any client has used
410     PROTMESSID_CLM_REQ_CHANNEL_LEVEL_LIST to opt in
411 
412     the server should issue the message only to a client that has used
413     PROTMESSID_CLM_REQ_CHANNEL_LEVEL_LIST to opt in
414 
415 
416 - PROTMESSID_CLM_REGISTER_SERVER_RESP: result of registration request
417 
418     +---------------+
419     | 1 byte status |
420     +---------------+
421 
422     - "status":
423       Values of ESvrRegResult:
424       0 - success
425       1 - failed due to directory server list being full
426       2 - your server version is too old
427       3 - registration requirements not fulfilled
428 
429     Note: the directory server may send this message in response to a
430           PROTMESSID_CLM_REGISTER_SERVER request.
431           Where not received, the registering server may only retry up to
432           five times for one registration request at 500ms intervals.
433           Beyond this, it should "ping" every 15 minutes
434           (standard re-registration timeout).
435 */
436 
437 #include "protocol.h"
438 
439 /* Implementation *************************************************************/
CProtocol()440 CProtocol::CProtocol()
441 {
442     // allocate worst case memory for split part messages
443     vecbySplitMessageStorage.Init ( MAX_SIZE_BYTES_NETW_BUF );
444 
445     Reset();
446 
447     // Connections -------------------------------------------------------------
448     QObject::connect ( &TimerSendMess, &QTimer::timeout, this, &CProtocol::OnTimerSendMess );
449 }
450 
Reset()451 void CProtocol::Reset()
452 {
453     QMutexLocker locker ( &Mutex );
454 
455     // prepare internal variables for initial protocol transfer
456     iCounter               = 0;
457     iOldRecID              = PROTMESSID_ILLEGAL;
458     iOldRecCnt             = 0;
459     iSplitMessageCnt       = 0;
460     iSplitMessageDataIndex = 0;
461     bSplitMessageSupported = false; // compatilibity to old versions
462 
463     // delete complete "send message queue"
464     SendMessQueue.clear();
465 }
466 
EnqueueMessage(CVector<uint8_t> & vecMessage,const int iCnt,const int iID)467 void CProtocol::EnqueueMessage ( CVector<uint8_t>& vecMessage, const int iCnt, const int iID )
468 {
469     bool bListWasEmpty;
470 
471     Mutex.lock();
472     {
473         // check if list is empty so that we have to initiate a send process
474         bListWasEmpty = SendMessQueue.empty();
475 
476         // create send message object for the queue
477         CSendMessage SendMessageObj ( vecMessage, iCnt, iID );
478 
479         // we want to have a FIFO: we add at the end and take from the beginning
480         SendMessQueue.push_back ( SendMessageObj );
481     }
482     Mutex.unlock();
483 
484     // if list was empty, initiate send process
485     if ( bListWasEmpty )
486     {
487         SendMessage();
488     }
489 }
490 
SendMessage()491 void CProtocol::SendMessage()
492 {
493     CVector<uint8_t> vecMessage;
494     bool             bSendMess = false;
495 
496     Mutex.lock();
497     {
498         // we have to check that list is not empty, since in another thread the
499         // last element of the list might have been erased
500         if ( !SendMessQueue.empty() )
501         {
502             vecMessage.Init ( SendMessQueue.front().vecMessage.Size() );
503             vecMessage = SendMessQueue.front().vecMessage;
504 
505             // start time-out timer if not active
506             if ( !TimerSendMess.isActive() )
507             {
508                 TimerSendMess.start ( SEND_MESS_TIMEOUT_MS );
509             }
510 
511             bSendMess = true;
512         }
513         else
514         {
515             // no message to send, stop timer
516             TimerSendMess.stop();
517         }
518     }
519     Mutex.unlock();
520 
521     if ( bSendMess )
522     {
523         // send message
524         emit MessReadyForSending ( vecMessage );
525     }
526 }
527 
CreateAndSendMessage(const int iID,const CVector<uint8_t> & vecData)528 void CProtocol::CreateAndSendMessage ( const int iID, const CVector<uint8_t>& vecData )
529 {
530     CVector<uint8_t> vecNewMessage;
531     int              iCurCounter;
532     const int        iDataLen = vecData.Size();
533 
534     // check if message has to be split because it is too large
535     if ( bSplitMessageSupported && ( iDataLen > MESS_SPLIT_PART_SIZE_BYTES ) )
536     {
537         CVector<uint8_t> vecNewSplitMessage;
538         int              iStartIndexInData = 0; // init index
539 
540         // calculate the number of split parts
541         const int iNumParts = static_cast<int> ( std::ceil ( static_cast<double> ( iDataLen ) / MESS_SPLIT_PART_SIZE_BYTES ) );
542 
543         for ( int iSplitCnt = 0; iSplitCnt < iNumParts; iSplitCnt++ )
544         {
545             // the split part size may be smaller for the last part
546             int iCurPartSize = MESS_SPLIT_PART_SIZE_BYTES;
547 
548             if ( iDataLen - iStartIndexInData < MESS_SPLIT_PART_SIZE_BYTES )
549             {
550                 iCurPartSize = iDataLen - iStartIndexInData;
551             }
552 
553             GenSplitMessageContainer ( vecNewSplitMessage, iID, iNumParts, iSplitCnt, vecData, iStartIndexInData, iCurPartSize );
554 
555             // increment the start index of the source data by the last part size
556             iStartIndexInData += iCurPartSize;
557 
558             Mutex.lock();
559             {
560                 // store current counter value
561                 iCurCounter = iCounter;
562 
563                 // increase counter (wraps around automatically)
564                 iCounter++;
565             }
566             Mutex.unlock();
567 
568             // build complete message
569             GenMessageFrame ( vecNewMessage, iCurCounter, PROTMESSID_SPECIAL_SPLIT_MESSAGE, vecNewSplitMessage );
570 
571             // enqueue message
572             EnqueueMessage ( vecNewMessage, iCurCounter, PROTMESSID_SPECIAL_SPLIT_MESSAGE );
573         }
574     }
575     else
576     {
577         Mutex.lock();
578         {
579             // store current counter value
580             iCurCounter = iCounter;
581 
582             // increase counter (wraps around automatically)
583             iCounter++;
584         }
585         Mutex.unlock();
586 
587         // build complete message
588         GenMessageFrame ( vecNewMessage, iCurCounter, iID, vecData );
589 
590         // enqueue message
591         EnqueueMessage ( vecNewMessage, iCurCounter, iID );
592     }
593 }
594 
CreateAndImmSendAcknMess(const int & iID,const int & iCnt)595 void CProtocol::CreateAndImmSendAcknMess ( const int& iID, const int& iCnt )
596 {
597     CVector<uint8_t> vecAcknMessage;
598     CVector<uint8_t> vecData ( 2 ); // 2 bytes of data
599     int              iPos = 0;      // init position pointer
600 
601     // build data vector
602     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iID ), 2 );
603 
604     // build complete message
605     GenMessageFrame ( vecAcknMessage, iCnt, PROTMESSID_ACKN, vecData );
606 
607     // immediately send acknowledge message
608     emit MessReadyForSending ( vecAcknMessage );
609 }
610 
CreateAndImmSendConLessMessage(const int iID,const CVector<uint8_t> & vecData,const CHostAddress & InetAddr)611 void CProtocol::CreateAndImmSendConLessMessage ( const int iID, const CVector<uint8_t>& vecData, const CHostAddress& InetAddr )
612 {
613     CVector<uint8_t> vecNewMessage;
614 
615     // build complete message (counter per definition=0 for connection less
616     // messages)
617     GenMessageFrame ( vecNewMessage, 0, iID, vecData );
618 
619     // immediately send message
620     emit CLMessReadyForSending ( InetAddr, vecNewMessage );
621 }
622 
ParseMessageBody(const CVector<uint8_t> & vecbyMesBodyData,const int iRecCounter,const int iRecID)623 void CProtocol::ParseMessageBody ( const CVector<uint8_t>& vecbyMesBodyData, const int iRecCounter, const int iRecID )
624 {
625     // clang-format off
626 /*
627 // TEST channel implementation: randomly delete protocol messages (50 % loss)
628 if ( rand() < ( RAND_MAX / 2 ) ) return false;
629 */
630     // clang-format on
631 
632     // In case we received a message and returned an answer but our answer
633     // did not make it to the receiver, he will resend his message. We check
634     // here if the message is the same as the old one, and if this is the
635     // case, just resend our old answer again
636     if ( ( iOldRecID == iRecID ) && ( iOldRecCnt == iRecCounter ) )
637     {
638         // acknowledgments are not acknowledged
639         if ( iRecID != PROTMESSID_ACKN )
640         {
641             // resend acknowledgement
642             CreateAndImmSendAcknMess ( iRecID, iRecCounter );
643         }
644     }
645     else
646     {
647         // special treatment for acknowledge messages
648         if ( iRecID == PROTMESSID_ACKN )
649         {
650             // check size
651             if ( vecbyMesBodyData.Size() != 2 )
652             {
653                 return;
654             }
655 
656             // extract data from stream and emit signal for received value
657             bool      bSendNextMess = false;
658             int       iPos          = 0;
659             const int iData         = static_cast<int> ( GetValFromStream ( vecbyMesBodyData, iPos, 2 ) );
660 
661             Mutex.lock();
662             {
663                 // check if this is the correct acknowledgment
664                 if ( !SendMessQueue.empty() )
665                 {
666                     if ( ( SendMessQueue.front().iCnt == iRecCounter ) && ( SendMessQueue.front().iID == iData ) )
667                     {
668                         // message acknowledged, remove from queue
669                         SendMessQueue.pop_front();
670 
671                         // send next message in queue
672                         bSendNextMess = true;
673                     }
674                 }
675             }
676             Mutex.unlock();
677 
678             if ( bSendNextMess )
679             {
680                 SendMessage();
681             }
682         }
683         else
684         {
685             CVector<uint8_t> vecbyMesBodyDataSplitMess;
686             int              iRecIDModified   = iRecID;
687             bool             bEvaluateMessage = false;
688 
689             // check for special ID first
690             if ( iRecID == PROTMESSID_SPECIAL_SPLIT_MESSAGE )
691             {
692                 // Split message management ------------------------------------
693                 int iOriginalID;
694                 int iReceivedNumParts;
695                 int iReceivedSplitCnt;
696                 int iCurPartSize;
697 
698                 if ( !ParseSplitMessageContainer ( vecbyMesBodyData,
699                                                    vecbySplitMessageStorage,
700                                                    iSplitMessageDataIndex,
701                                                    iOriginalID,
702                                                    iReceivedNumParts,
703                                                    iReceivedSplitCnt,
704                                                    iCurPartSize ) )
705                 {
706                     // consistency checks
707                     if ( ( iSplitMessageCnt != iReceivedSplitCnt ) || ( iSplitMessageCnt >= iReceivedNumParts ) ||
708                          ( iSplitMessageCnt >= MAX_NUM_MESS_SPLIT_PARTS ) )
709                     {
710                         // in case of an error we reset the split message counter
711                         iSplitMessageCnt       = 0;
712                         iSplitMessageDataIndex = 0;
713                     }
714                     else
715                     {
716                         // update counter and message data index since we have received a valid new part
717                         iSplitMessageCnt++;
718                         iSplitMessageDataIndex += iCurPartSize;
719 
720                         // check if the split part messages was completely received
721                         if ( iSplitMessageCnt == iReceivedNumParts )
722                         {
723                             // the split message is completely received, copy data for parsing
724                             vecbyMesBodyDataSplitMess.Init ( iSplitMessageDataIndex );
725 
726                             std::copy ( vecbySplitMessageStorage.begin(),
727                                         vecbySplitMessageStorage.begin() + iSplitMessageDataIndex,
728                                         vecbyMesBodyDataSplitMess.begin() );
729 
730                             // the received ID is still PROTMESSID_SPECIAL_SPLIT_MESSAGE, set it to
731                             // the ID of the original reconstructed split message now
732                             iRecIDModified = iOriginalID;
733 
734                             // the complete split message was reconstructed, reset the counter for
735                             // the next split message
736                             iSplitMessageCnt       = 0;
737                             iSplitMessageDataIndex = 0;
738                             bEvaluateMessage       = true;
739                         }
740                     }
741                 }
742             }
743             else
744             {
745                 // a non-split message was received, reset split message counter and directly evaluate message
746                 iSplitMessageCnt       = 0;
747                 iSplitMessageDataIndex = 0;
748                 bEvaluateMessage       = true;
749             }
750 
751             if ( bEvaluateMessage )
752             {
753                 // use a reference to either the original data vector or the reconstructed
754                 // split message to avoid unnecessary copying
755                 const CVector<uint8_t>& vecbyMesBodyDataRef =
756                     ( iRecID == PROTMESSID_SPECIAL_SPLIT_MESSAGE ) ? vecbyMesBodyDataSplitMess : vecbyMesBodyData;
757 
758                 // check which type of message we received and do action
759                 switch ( iRecIDModified )
760                 {
761                 case PROTMESSID_JITT_BUF_SIZE:
762                     EvaluateJitBufMes ( vecbyMesBodyDataRef );
763                     break;
764 
765                 case PROTMESSID_REQ_JITT_BUF_SIZE:
766                     EvaluateReqJitBufMes();
767                     break;
768 
769                 case PROTMESSID_CLIENT_ID:
770                     EvaluateClientIDMes ( vecbyMesBodyDataRef );
771                     break;
772 
773                 case PROTMESSID_CHANNEL_GAIN:
774                     EvaluateChanGainMes ( vecbyMesBodyDataRef );
775                     break;
776 
777                 case PROTMESSID_CHANNEL_PAN:
778                     EvaluateChanPanMes ( vecbyMesBodyDataRef );
779                     break;
780 
781                 case PROTMESSID_MUTE_STATE_CHANGED:
782                     EvaluateMuteStateHasChangedMes ( vecbyMesBodyDataRef );
783                     break;
784 
785                 case PROTMESSID_CONN_CLIENTS_LIST:
786                     EvaluateConClientListMes ( vecbyMesBodyDataRef );
787                     break;
788 
789                 case PROTMESSID_REQ_CONN_CLIENTS_LIST:
790                     EvaluateReqConnClientsList();
791                     break;
792 
793                 case PROTMESSID_CHANNEL_INFOS:
794                     EvaluateChanInfoMes ( vecbyMesBodyDataRef );
795                     break;
796 
797                 case PROTMESSID_REQ_CHANNEL_INFOS:
798                     EvaluateReqChanInfoMes();
799                     break;
800 
801                 case PROTMESSID_CHAT_TEXT:
802                     EvaluateChatTextMes ( vecbyMesBodyDataRef );
803                     break;
804 
805                 case PROTMESSID_NETW_TRANSPORT_PROPS:
806                     EvaluateNetwTranspPropsMes ( vecbyMesBodyDataRef );
807                     break;
808 
809                 case PROTMESSID_REQ_NETW_TRANSPORT_PROPS:
810                     EvaluateReqNetwTranspPropsMes();
811                     break;
812 
813                 case PROTMESSID_REQ_SPLIT_MESS_SUPPORT:
814                     EvaluateReqSplitMessSupportMes();
815                     break;
816 
817                 case PROTMESSID_SPLIT_MESS_SUPPORTED:
818                     EvaluateSplitMessSupportedMes();
819                     break;
820 
821                 case PROTMESSID_LICENCE_REQUIRED:
822                     EvaluateLicenceRequiredMes ( vecbyMesBodyDataRef );
823                     break;
824 
825                 case PROTMESSID_VERSION_AND_OS:
826                     EvaluateVersionAndOSMes ( vecbyMesBodyDataRef );
827                     break;
828 
829                 case PROTMESSID_RECORDER_STATE:
830                     EvaluateRecorderStateMes ( vecbyMesBodyDataRef );
831                     break;
832                 }
833             }
834 
835             // immediately send acknowledge message
836             CreateAndImmSendAcknMess ( iRecID, iRecCounter );
837 
838             // save current message ID and counter to find out if message
839             // was resent
840             iOldRecID  = iRecID;
841             iOldRecCnt = iRecCounter;
842         }
843     }
844 }
845 
ParseConnectionLessMessageBody(const CVector<uint8_t> & vecbyMesBodyData,const int iRecID,const CHostAddress & InetAddr)846 void CProtocol::ParseConnectionLessMessageBody ( const CVector<uint8_t>& vecbyMesBodyData, const int iRecID, const CHostAddress& InetAddr )
847 {
848     // clang-format off
849 /*
850 // TEST channel implementation: randomly delete protocol messages (50 % loss)
851 if ( rand() < ( RAND_MAX / 2 ) ) return false;
852 */
853     // clang-format on
854 
855     // check which type of message we received and do action
856     switch ( iRecID )
857     {
858     case PROTMESSID_CLM_PING_MS:
859         EvaluateCLPingMes ( InetAddr, vecbyMesBodyData );
860         break;
861 
862     case PROTMESSID_CLM_PING_MS_WITHNUMCLIENTS:
863         EvaluateCLPingWithNumClientsMes ( InetAddr, vecbyMesBodyData );
864         break;
865 
866     case PROTMESSID_CLM_SERVER_FULL:
867         EvaluateCLServerFullMes();
868         break;
869 
870     case PROTMESSID_CLM_SERVER_LIST:
871         EvaluateCLServerListMes ( InetAddr, vecbyMesBodyData );
872         break;
873 
874     case PROTMESSID_CLM_RED_SERVER_LIST:
875         EvaluateCLRedServerListMes ( InetAddr, vecbyMesBodyData );
876         break;
877 
878     case PROTMESSID_CLM_REQ_SERVER_LIST:
879         EvaluateCLReqServerListMes ( InetAddr );
880         break;
881 
882     case PROTMESSID_CLM_SEND_EMPTY_MESSAGE:
883         EvaluateCLSendEmptyMesMes ( vecbyMesBodyData );
884         break;
885 
886     case PROTMESSID_CLM_REGISTER_SERVER:
887         EvaluateCLRegisterServerMes ( InetAddr, vecbyMesBodyData );
888         break;
889 
890     case PROTMESSID_CLM_REGISTER_SERVER_EX:
891         EvaluateCLRegisterServerExMes ( InetAddr, vecbyMesBodyData );
892         break;
893 
894     case PROTMESSID_CLM_UNREGISTER_SERVER:
895         EvaluateCLUnregisterServerMes ( InetAddr );
896         break;
897 
898     case PROTMESSID_CLM_DISCONNECTION:
899         EvaluateCLDisconnectionMes ( InetAddr );
900         break;
901 
902     case PROTMESSID_CLM_VERSION_AND_OS:
903         EvaluateCLVersionAndOSMes ( InetAddr, vecbyMesBodyData );
904         break;
905 
906     case PROTMESSID_CLM_REQ_VERSION_AND_OS:
907         EvaluateCLReqVersionAndOSMes ( InetAddr );
908         break;
909 
910     case PROTMESSID_CLM_CONN_CLIENTS_LIST:
911         EvaluateCLConnClientsListMes ( InetAddr, vecbyMesBodyData );
912         break;
913 
914     case PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST:
915         EvaluateCLReqConnClientsListMes ( InetAddr );
916         break;
917 
918     case PROTMESSID_CLM_CHANNEL_LEVEL_LIST:
919         EvaluateCLChannelLevelListMes ( InetAddr, vecbyMesBodyData );
920         break;
921 
922     case PROTMESSID_CLM_REGISTER_SERVER_RESP:
923         EvaluateCLRegisterServerResp ( InetAddr, vecbyMesBodyData );
924         break;
925     }
926 }
927 
928 /******************************************************************************\
929 * Access functions for creating and parsing messages                           *
930 \******************************************************************************/
CreateJitBufMes(const int iJitBufSize)931 void CProtocol::CreateJitBufMes ( const int iJitBufSize )
932 {
933     CVector<uint8_t> vecData ( 2 ); // 2 bytes of data
934     int              iPos = 0;      // init position pointer
935 
936     // build data vector
937     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iJitBufSize ), 2 );
938 
939     CreateAndSendMessage ( PROTMESSID_JITT_BUF_SIZE, vecData );
940 }
941 
EvaluateJitBufMes(const CVector<uint8_t> & vecData)942 bool CProtocol::EvaluateJitBufMes ( const CVector<uint8_t>& vecData )
943 {
944     int iPos = 0; // init position pointer
945 
946     // check size
947     if ( vecData.Size() != 2 )
948     {
949         return true; // return error code
950     }
951 
952     // extract jitter buffer size
953     const int iData = static_cast<int> ( GetValFromStream ( vecData, iPos, 2 ) );
954 
955     if ( ( ( iData < MIN_NET_BUF_SIZE_NUM_BL ) || ( iData > MAX_NET_BUF_SIZE_NUM_BL ) ) && ( iData != AUTO_NET_BUF_SIZE_FOR_PROTOCOL ) )
956     {
957         return true; // return error code
958     }
959 
960     // invoke message action
961     emit ChangeJittBufSize ( iData );
962 
963     return false; // no error
964 }
965 
CreateReqJitBufMes()966 void CProtocol::CreateReqJitBufMes() { CreateAndSendMessage ( PROTMESSID_REQ_JITT_BUF_SIZE, CVector<uint8_t> ( 0 ) ); }
967 
EvaluateReqJitBufMes()968 bool CProtocol::EvaluateReqJitBufMes()
969 {
970     // invoke message action
971     emit ReqJittBufSize();
972 
973     return false; // no error
974 }
975 
CreateClientIDMes(const int iChanID)976 void CProtocol::CreateClientIDMes ( const int iChanID )
977 {
978     CVector<uint8_t> vecData ( 1 ); // 1 byte of data
979     int              iPos = 0;      // init position pointer
980 
981     // build data vector
982     // channel ID
983     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iChanID ), 1 );
984 
985     CreateAndSendMessage ( PROTMESSID_CLIENT_ID, vecData );
986 }
987 
EvaluateClientIDMes(const CVector<uint8_t> & vecData)988 bool CProtocol::EvaluateClientIDMes ( const CVector<uint8_t>& vecData )
989 {
990     int iPos = 0; // init position pointer
991 
992     // check size
993     if ( vecData.Size() != 1 )
994     {
995         return true; // return error code
996     }
997 
998     // channel ID
999     const int iCurID = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
1000 
1001     // invoke message action
1002     emit ClientIDReceived ( iCurID );
1003 
1004     return false; // no error
1005 }
1006 
CreateChanGainMes(const int iChanID,const float fGain)1007 void CProtocol::CreateChanGainMes ( const int iChanID, const float fGain )
1008 {
1009     CVector<uint8_t> vecData ( 3 ); // 3 bytes of data
1010     int              iPos = 0;      // init position pointer
1011 
1012     // build data vector
1013     // channel ID
1014     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iChanID ), 1 );
1015 
1016     // actual gain, we convert from double with range 0..1 to integer
1017     const int iCurGain = static_cast<int> ( fGain * ( 1 << 15 ) );
1018 
1019     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iCurGain ), 2 );
1020 
1021     CreateAndSendMessage ( PROTMESSID_CHANNEL_GAIN, vecData );
1022 }
1023 
EvaluateChanGainMes(const CVector<uint8_t> & vecData)1024 bool CProtocol::EvaluateChanGainMes ( const CVector<uint8_t>& vecData )
1025 {
1026     int iPos = 0; // init position pointer
1027 
1028     // check size
1029     if ( vecData.Size() != 3 )
1030     {
1031         return true; // return error code
1032     }
1033 
1034     // channel ID
1035     const int iCurID = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
1036 
1037     // gain (read integer value)
1038     const int iData = static_cast<int> ( GetValFromStream ( vecData, iPos, 2 ) );
1039 
1040     // we convert the gain from integer to double with range 0..1
1041     const float fNewGain = static_cast<float> ( iData ) / ( 1 << 15 );
1042 
1043     // invoke message action
1044     emit ChangeChanGain ( iCurID, fNewGain );
1045 
1046     return false; // no error
1047 }
1048 
CreateChanPanMes(const int iChanID,const float fPan)1049 void CProtocol::CreateChanPanMes ( const int iChanID, const float fPan )
1050 {
1051     CVector<uint8_t> vecData ( 3 ); // 3 bytes of data
1052     int              iPos = 0;      // init position pointer
1053 
1054     // build data vector
1055     // channel ID
1056     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iChanID ), 1 );
1057 
1058     // actual pan, we convert from double with range 0..1 to integer
1059     const int iCurPan = static_cast<int> ( fPan * ( 1 << 15 ) );
1060 
1061     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iCurPan ), 2 );
1062 
1063     CreateAndSendMessage ( PROTMESSID_CHANNEL_PAN, vecData );
1064 }
1065 
EvaluateChanPanMes(const CVector<uint8_t> & vecData)1066 bool CProtocol::EvaluateChanPanMes ( const CVector<uint8_t>& vecData )
1067 {
1068     int iPos = 0; // init position pointer
1069 
1070     // check size
1071     if ( vecData.Size() != 3 )
1072     {
1073         return true; // return error code
1074     }
1075 
1076     // channel ID
1077     const int iCurID = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
1078 
1079     // pan (read integer value)
1080     const int iData = static_cast<int> ( GetValFromStream ( vecData, iPos, 2 ) );
1081 
1082     // we convert the pan from integer to double with range 0..1
1083     const float fNewPan = static_cast<float> ( iData ) / ( 1 << 15 );
1084 
1085     // invoke message action
1086     emit ChangeChanPan ( iCurID, fNewPan );
1087 
1088     return false; // no error
1089 }
1090 
CreateMuteStateHasChangedMes(const int iChanID,const bool bIsMuted)1091 void CProtocol::CreateMuteStateHasChangedMes ( const int iChanID, const bool bIsMuted )
1092 {
1093     CVector<uint8_t> vecData ( 2 ); // 2 bytes of data
1094     int              iPos = 0;      // init position pointer
1095 
1096     // build data vector
1097     // channel ID
1098     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iChanID ), 1 );
1099 
1100     // mute state
1101     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( bIsMuted ), 1 );
1102 
1103     CreateAndSendMessage ( PROTMESSID_MUTE_STATE_CHANGED, vecData );
1104 }
1105 
EvaluateMuteStateHasChangedMes(const CVector<uint8_t> & vecData)1106 bool CProtocol::EvaluateMuteStateHasChangedMes ( const CVector<uint8_t>& vecData )
1107 {
1108     int iPos = 0; // init position pointer
1109 
1110     // check size
1111     if ( vecData.Size() != 2 )
1112     {
1113         return true; // return error code
1114     }
1115 
1116     // channel ID
1117     const int iCurID = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
1118 
1119     // mute state
1120     const bool bIsMuted = static_cast<bool> ( GetValFromStream ( vecData, iPos, 1 ) );
1121 
1122     // invoke message action
1123     emit MuteStateHasChangedReceived ( iCurID, bIsMuted );
1124 
1125     return false; // no error
1126 }
1127 
CreateConClientListMes(const CVector<CChannelInfo> & vecChanInfo)1128 void CProtocol::CreateConClientListMes ( const CVector<CChannelInfo>& vecChanInfo )
1129 {
1130     const int iNumClients = vecChanInfo.Size();
1131 
1132     // build data vector
1133     CVector<uint8_t> vecData ( 0 );
1134     int              iPos = 0; // init position pointer
1135 
1136     for ( int i = 0; i < iNumClients; i++ )
1137     {
1138         // convert strings to utf-8
1139         const QByteArray strUTF8Name = vecChanInfo[i].strName.toUtf8();
1140         const QByteArray strUTF8City = vecChanInfo[i].strCity.toUtf8();
1141 
1142         // size of current list entry
1143         const int iCurListEntrLen = 1 +                      // chan ID
1144                                     2 +                      // country
1145                                     4 +                      // instrument
1146                                     1 +                      // skill level
1147                                     4 +                      // IP address
1148                                     2 + strUTF8Name.size() + // utf-8 str. size / str.
1149                                     2 + strUTF8City.size();  // utf-8 str. size / str.
1150 
1151         // make space for new data
1152         vecData.Enlarge ( iCurListEntrLen );
1153 
1154         // channel ID (1 byte)
1155         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecChanInfo[i].iChanID ), 1 );
1156 
1157         // country (2 bytes)
1158         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecChanInfo[i].eCountry ), 2 );
1159 
1160         // instrument (4 bytes)
1161         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecChanInfo[i].iInstrument ), 4 );
1162 
1163         // skill level (1 byte)
1164         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecChanInfo[i].eSkillLevel ), 1 );
1165 
1166         // used to be IP address before #316 (4 bytes)
1167         PutValOnStream ( vecData, iPos, 0, 4 );
1168 
1169         // name
1170         PutStringUTF8OnStream ( vecData, iPos, strUTF8Name );
1171 
1172         // city
1173         PutStringUTF8OnStream ( vecData, iPos, strUTF8City );
1174     }
1175 
1176     CreateAndSendMessage ( PROTMESSID_CONN_CLIENTS_LIST, vecData );
1177 }
1178 
EvaluateConClientListMes(const CVector<uint8_t> & vecData)1179 bool CProtocol::EvaluateConClientListMes ( const CVector<uint8_t>& vecData )
1180 {
1181     int                   iPos     = 0; // init position pointer
1182     const int             iDataLen = vecData.Size();
1183     CVector<CChannelInfo> vecChanInfo ( 0 );
1184 
1185     while ( iPos < iDataLen )
1186     {
1187         // check size (the next 12 bytes)
1188         if ( ( iDataLen - iPos ) < 12 )
1189         {
1190             return true; // return error code
1191         }
1192 
1193         // channel ID (1 byte)
1194         const int iChanID = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
1195 
1196         // country (2 bytes)
1197         const QLocale::Country eCountry = static_cast<QLocale::Country> ( GetValFromStream ( vecData, iPos, 2 ) );
1198 
1199         // instrument (4 bytes)
1200         const int iInstrument = static_cast<int> ( GetValFromStream ( vecData, iPos, 4 ) );
1201 
1202         // skill level (1 byte)
1203         const ESkillLevel eSkillLevel = static_cast<ESkillLevel> ( GetValFromStream ( vecData, iPos, 1 ) );
1204 
1205         // used to be IP address, zero since #316 (4 bytes)
1206         iPos += 4;
1207 
1208         // name
1209         QString strCurName;
1210         if ( GetStringFromStream ( vecData, iPos, MAX_LEN_FADER_TAG, strCurName ) )
1211         {
1212             return true; // return error code
1213         }
1214 
1215         // city
1216         QString strCurCity;
1217         if ( GetStringFromStream ( vecData, iPos, MAX_LEN_SERVER_CITY, strCurCity ) )
1218         {
1219             return true; // return error code
1220         }
1221 
1222         // add channel information to vector
1223         vecChanInfo.Add ( CChannelInfo ( iChanID, strCurName, eCountry, strCurCity, iInstrument, eSkillLevel ) );
1224     }
1225 
1226     // check size: all data is read, the position must now be at the end
1227     if ( iPos != iDataLen )
1228     {
1229         return true; // return error code
1230     }
1231 
1232     // invoke message action
1233     emit ConClientListMesReceived ( vecChanInfo );
1234 
1235     return false; // no error
1236 }
1237 
CreateReqConnClientsList()1238 void CProtocol::CreateReqConnClientsList() { CreateAndSendMessage ( PROTMESSID_REQ_CONN_CLIENTS_LIST, CVector<uint8_t> ( 0 ) ); }
1239 
EvaluateReqConnClientsList()1240 bool CProtocol::EvaluateReqConnClientsList()
1241 {
1242     // invoke message action
1243     emit ReqConnClientsList();
1244 
1245     return false; // no error
1246 }
1247 
CreateChanInfoMes(const CChannelCoreInfo ChanInfo)1248 void CProtocol::CreateChanInfoMes ( const CChannelCoreInfo ChanInfo )
1249 {
1250     int iPos = 0; // init position pointer
1251 
1252     // convert strings to utf-8
1253     const QByteArray strUTF8Name = ChanInfo.strName.toUtf8();
1254     const QByteArray strUTF8City = ChanInfo.strCity.toUtf8();
1255 
1256     // size of current list entry
1257     const int iEntrLen = 2 +                      // country
1258                          4 +                      // instrument
1259                          1 +                      // skill level
1260                          2 + strUTF8Name.size() + // utf-8 str. size / str.
1261                          2 + strUTF8City.size();  // utf-8 str. size / str.
1262 
1263     // build data vector
1264     CVector<uint8_t> vecData ( iEntrLen );
1265 
1266     // country (2 bytes)
1267     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( ChanInfo.eCountry ), 2 );
1268 
1269     // instrument (4 bytes)
1270     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( ChanInfo.iInstrument ), 4 );
1271 
1272     // skill level (1 byte)
1273     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( ChanInfo.eSkillLevel ), 1 );
1274 
1275     // name
1276     PutStringUTF8OnStream ( vecData, iPos, strUTF8Name );
1277 
1278     // city
1279     PutStringUTF8OnStream ( vecData, iPos, strUTF8City );
1280 
1281     CreateAndSendMessage ( PROTMESSID_CHANNEL_INFOS, vecData );
1282 }
1283 
EvaluateChanInfoMes(const CVector<uint8_t> & vecData)1284 bool CProtocol::EvaluateChanInfoMes ( const CVector<uint8_t>& vecData )
1285 {
1286     int              iPos     = 0; // init position pointer
1287     const int        iDataLen = vecData.Size();
1288     CChannelCoreInfo ChanInfo;
1289 
1290     // check size (the first 7 bytes)
1291     if ( iDataLen < 7 )
1292     {
1293         return true; // return error code
1294     }
1295 
1296     // country (2 bytes)
1297     ChanInfo.eCountry = static_cast<QLocale::Country> ( GetValFromStream ( vecData, iPos, 2 ) );
1298 
1299     // instrument (4 bytes)
1300     ChanInfo.iInstrument = static_cast<int> ( GetValFromStream ( vecData, iPos, 4 ) );
1301 
1302     // skill level (1 byte)
1303     ChanInfo.eSkillLevel = static_cast<ESkillLevel> ( GetValFromStream ( vecData, iPos, 1 ) );
1304 
1305     // name
1306     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_FADER_TAG, ChanInfo.strName ) )
1307     {
1308         return true; // return error code
1309     }
1310 
1311     // city
1312     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_SERVER_CITY, ChanInfo.strCity ) )
1313     {
1314         return true; // return error code
1315     }
1316 
1317     // check size: all data is read, the position must now be at the end
1318     if ( iPos != iDataLen )
1319     {
1320         return true; // return error code
1321     }
1322 
1323     // invoke message action
1324     emit ChangeChanInfo ( ChanInfo );
1325 
1326     return false; // no error
1327 }
1328 
CreateReqChanInfoMes()1329 void CProtocol::CreateReqChanInfoMes() { CreateAndSendMessage ( PROTMESSID_REQ_CHANNEL_INFOS, CVector<uint8_t> ( 0 ) ); }
1330 
EvaluateReqChanInfoMes()1331 bool CProtocol::EvaluateReqChanInfoMes()
1332 {
1333     // invoke message action
1334     emit ReqChanInfo();
1335 
1336     return false; // no error
1337 }
1338 
CreateChatTextMes(const QString strChatText)1339 void CProtocol::CreateChatTextMes ( const QString strChatText )
1340 {
1341     int iPos = 0; // init position pointer
1342 
1343     // convert chat text string to utf-8
1344     const QByteArray strUTF8ChatText = strChatText.toUtf8();
1345 
1346     const int iStrUTF8Len = strUTF8ChatText.size(); // get utf-8 str. size / string
1347 
1348     // size of message body
1349     const int iEntrLen = 2 + iStrUTF8Len; // utf-8 str. size / string
1350 
1351     // build data vector
1352     CVector<uint8_t> vecData ( iEntrLen );
1353 
1354     // chat text
1355     PutStringUTF8OnStream ( vecData, iPos, strUTF8ChatText );
1356 
1357     CreateAndSendMessage ( PROTMESSID_CHAT_TEXT, vecData );
1358 }
1359 
EvaluateChatTextMes(const CVector<uint8_t> & vecData)1360 bool CProtocol::EvaluateChatTextMes ( const CVector<uint8_t>& vecData )
1361 {
1362     int iPos = 0; // init position pointer
1363 
1364     // chat text
1365     QString strChatText;
1366     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_CHAT_TEXT_PLUS_HTML, strChatText ) )
1367     {
1368         return true; // return error code
1369     }
1370 
1371     // check size: all data is read, the position must now be at the end
1372     if ( iPos != vecData.Size() )
1373     {
1374         return true; // return error code
1375     }
1376 
1377     // invoke message action
1378     emit ChatTextReceived ( strChatText );
1379 
1380     return false; // no error
1381 }
1382 
CreateNetwTranspPropsMes(const CNetworkTransportProps & NetTrProps)1383 void CProtocol::CreateNetwTranspPropsMes ( const CNetworkTransportProps& NetTrProps )
1384 {
1385     int iPos = 0; // init position pointer
1386 
1387     // size of current message body
1388     const int iEntrLen = 4 + // netw size
1389                          2 + // block size fact
1390                          1 + // num chan
1391                          4 + // sam rate
1392                          2 + // audiocod type
1393                          2 + // version
1394                          4;  // audiocod arg
1395 
1396     // build data vector
1397     CVector<uint8_t> vecData ( iEntrLen );
1398 
1399     // length of the base network packet (frame) in bytes (4 bytes)
1400     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( NetTrProps.iBaseNetworkPacketSize ), 4 );
1401 
1402     // block size factor (2 bytes)
1403     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( NetTrProps.iBlockSizeFact ), 2 );
1404 
1405     // number of channels of the audio signal, e.g. "2" is stereo (1 byte)
1406     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( NetTrProps.iNumAudioChannels ), 1 );
1407 
1408     // sample rate of the audio stream (4 bytes)
1409     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( NetTrProps.iSampleRate ), 4 );
1410 
1411     // audio coding type (2 bytes)
1412     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( NetTrProps.eAudioCodingType ), 2 );
1413 
1414     // flags (2 bytes)
1415     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( NetTrProps.eFlags ), 2 );
1416 
1417     // argument for the audio coder (4 bytes)
1418     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( NetTrProps.iAudioCodingArg ), 4 );
1419 
1420     CreateAndSendMessage ( PROTMESSID_NETW_TRANSPORT_PROPS, vecData );
1421 }
1422 
EvaluateNetwTranspPropsMes(const CVector<uint8_t> & vecData)1423 bool CProtocol::EvaluateNetwTranspPropsMes ( const CVector<uint8_t>& vecData )
1424 {
1425     int                    iPos = 0; // init position pointer
1426     CNetworkTransportProps ReceivedNetwTranspProps;
1427 
1428     // size of current message body
1429     const int iEntrLen = 4 + // netw size
1430                          2 + // block size fact
1431                          1 + // num chan
1432                          4 + // sam rate
1433                          2 + // audiocod type
1434                          2 + // flags
1435                          4;  // audiocod arg
1436 
1437     // check size
1438     if ( vecData.Size() != iEntrLen )
1439     {
1440         return true; // return error code
1441     }
1442 
1443     // length of the base network packet (frame) in bytes (4 bytes)
1444     ReceivedNetwTranspProps.iBaseNetworkPacketSize = static_cast<uint32_t> ( GetValFromStream ( vecData, iPos, 4 ) );
1445 
1446     // at least CELT_MINIMUM_NUM_BYTES bytes are required for the CELC codec
1447     if ( ( ReceivedNetwTranspProps.iBaseNetworkPacketSize < CELT_MINIMUM_NUM_BYTES ) ||
1448          ( ReceivedNetwTranspProps.iBaseNetworkPacketSize > MAX_SIZE_BYTES_NETW_BUF ) )
1449     {
1450         return true; // return error code
1451     }
1452 
1453     // block size factor (2 bytes)
1454     ReceivedNetwTranspProps.iBlockSizeFact = static_cast<uint16_t> ( GetValFromStream ( vecData, iPos, 2 ) );
1455 
1456     if ( ( ReceivedNetwTranspProps.iBlockSizeFact != FRAME_SIZE_FACTOR_PREFERRED ) &&
1457          ( ReceivedNetwTranspProps.iBlockSizeFact != FRAME_SIZE_FACTOR_DEFAULT ) &&
1458          ( ReceivedNetwTranspProps.iBlockSizeFact != FRAME_SIZE_FACTOR_SAFE ) )
1459     {
1460         return true; // return error code
1461     }
1462 
1463     // number of channels of the audio signal, only mono (1 channel) or
1464     // stereo (2 channels) allowed (1 byte)
1465     ReceivedNetwTranspProps.iNumAudioChannels = static_cast<uint32_t> ( GetValFromStream ( vecData, iPos, 1 ) );
1466 
1467     if ( ( ReceivedNetwTranspProps.iNumAudioChannels != 1 ) && ( ReceivedNetwTranspProps.iNumAudioChannels != 2 ) )
1468     {
1469         return true; // return error code
1470     }
1471 
1472     // sample rate of the audio stream (4 bytes)
1473     ReceivedNetwTranspProps.iSampleRate = static_cast<uint32_t> ( GetValFromStream ( vecData, iPos, 4 ) );
1474 
1475     // audio coding type (2 bytes) with error check
1476     const int iRecCodingType = static_cast<int> ( GetValFromStream ( vecData, iPos, 2 ) );
1477 
1478     // note that CT_NONE is not a valid setting but only used for server
1479     // initialization
1480     if ( ( iRecCodingType != CT_CELT ) && ( iRecCodingType != CT_OPUS ) && ( iRecCodingType != CT_OPUS64 ) )
1481     {
1482         return true;
1483     }
1484 
1485     ReceivedNetwTranspProps.eAudioCodingType = static_cast<EAudComprType> ( iRecCodingType );
1486 
1487     // flags (2 bytes)
1488     ReceivedNetwTranspProps.eFlags = static_cast<ENetwFlags> ( GetValFromStream ( vecData, iPos, 2 ) );
1489 
1490     // argument for the audio coder (4 bytes)
1491     ReceivedNetwTranspProps.iAudioCodingArg = static_cast<int32_t> ( GetValFromStream ( vecData, iPos, 4 ) );
1492 
1493     // invoke message action
1494     emit NetTranspPropsReceived ( ReceivedNetwTranspProps );
1495 
1496     return false; // no error
1497 }
1498 
CreateReqNetwTranspPropsMes()1499 void CProtocol::CreateReqNetwTranspPropsMes() { CreateAndSendMessage ( PROTMESSID_REQ_NETW_TRANSPORT_PROPS, CVector<uint8_t> ( 0 ) ); }
1500 
EvaluateReqNetwTranspPropsMes()1501 bool CProtocol::EvaluateReqNetwTranspPropsMes()
1502 {
1503     // invoke message action
1504     emit ReqNetTranspProps();
1505 
1506     return false; // no error
1507 }
1508 
CreateReqSplitMessSupportMes()1509 void CProtocol::CreateReqSplitMessSupportMes() { CreateAndSendMessage ( PROTMESSID_REQ_SPLIT_MESS_SUPPORT, CVector<uint8_t> ( 0 ) ); }
1510 
EvaluateReqSplitMessSupportMes()1511 bool CProtocol::EvaluateReqSplitMessSupportMes()
1512 {
1513     // invoke message action
1514     emit ReqSplitMessSupport();
1515 
1516     return false; // no error
1517 }
1518 
CreateSplitMessSupportedMes()1519 void CProtocol::CreateSplitMessSupportedMes() { CreateAndSendMessage ( PROTMESSID_SPLIT_MESS_SUPPORTED, CVector<uint8_t> ( 0 ) ); }
1520 
EvaluateSplitMessSupportedMes()1521 bool CProtocol::EvaluateSplitMessSupportedMes()
1522 {
1523     // invoke message action
1524     emit SplitMessSupported();
1525 
1526     return false; // no error
1527 }
1528 
CreateLicenceRequiredMes(const ELicenceType eLicenceType)1529 void CProtocol::CreateLicenceRequiredMes ( const ELicenceType eLicenceType )
1530 {
1531     CVector<uint8_t> vecData ( 1 ); // 1 bytes of data
1532     int              iPos = 0;      // init position pointer
1533 
1534     // build data vector
1535     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( eLicenceType ), 1 );
1536 
1537     CreateAndSendMessage ( PROTMESSID_LICENCE_REQUIRED, vecData );
1538 }
1539 
EvaluateLicenceRequiredMes(const CVector<uint8_t> & vecData)1540 bool CProtocol::EvaluateLicenceRequiredMes ( const CVector<uint8_t>& vecData )
1541 {
1542     int iPos = 0; // init position pointer
1543 
1544     // check size
1545     if ( vecData.Size() != 1 )
1546     {
1547         return true; // return error code
1548     }
1549 
1550     // extract licence type
1551     const ELicenceType eLicenceType = static_cast<ELicenceType> ( GetValFromStream ( vecData, iPos, 1 ) );
1552 
1553     if ( ( eLicenceType != LT_CREATIVECOMMONS ) && ( eLicenceType != LT_NO_LICENCE ) )
1554     {
1555         return true; // return error code
1556     }
1557 
1558     // invoke message action
1559     emit LicenceRequired ( eLicenceType );
1560 
1561     return false; // no error
1562 }
1563 
CreateOpusSupportedMes()1564 void CProtocol::CreateOpusSupportedMes() { CreateAndSendMessage ( PROTMESSID_OPUS_SUPPORTED, CVector<uint8_t> ( 0 ) ); }
1565 
1566 // TODO needed for compatibility to old servers >= 3.4.6 and <= 3.5.12
CreateReqChannelLevelListMes()1567 void CProtocol::CreateReqChannelLevelListMes()
1568 {
1569     CVector<uint8_t> vecData ( 1 ); // 1 byte of data
1570     int              iPos = 0;      // init position pointer
1571 
1572     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( true ), 1 );
1573 
1574     CreateAndSendMessage ( PROTMESSID_REQ_CHANNEL_LEVEL_LIST, vecData );
1575 }
1576 
CreateVersionAndOSMes()1577 void CProtocol::CreateVersionAndOSMes()
1578 {
1579     int iPos = 0; // init position pointer
1580 
1581     // get the version number string
1582     const QString strVerion = VERSION;
1583 
1584     // convert version string to utf-8
1585     const QByteArray strUTF8Version = strVerion.toUtf8();
1586 
1587     // size of current message body
1588     const int iEntrLen = 1 +                        // operating system
1589                          2 + strUTF8Version.size(); // version utf-8 str. size / string
1590 
1591     // build data vector
1592     CVector<uint8_t> vecData ( iEntrLen );
1593 
1594     // operating system (1 byte)
1595     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( COSUtil::GetOperatingSystem() ), 1 );
1596 
1597     // version
1598     PutStringUTF8OnStream ( vecData, iPos, strUTF8Version );
1599 
1600     CreateAndSendMessage ( PROTMESSID_VERSION_AND_OS, vecData );
1601 }
1602 
EvaluateVersionAndOSMes(const CVector<uint8_t> & vecData)1603 bool CProtocol::EvaluateVersionAndOSMes ( const CVector<uint8_t>& vecData )
1604 {
1605     int       iPos     = 0; // init position pointer
1606     const int iDataLen = vecData.Size();
1607 
1608     // check size (the first 1 byte)
1609     if ( iDataLen < 1 )
1610     {
1611         return true; // return error code
1612     }
1613 
1614     // operating system (1 byte)
1615     const COSUtil::EOpSystemType eOSType = static_cast<COSUtil::EOpSystemType> ( GetValFromStream ( vecData, iPos, 1 ) );
1616 
1617     // version text
1618     QString strVersion;
1619     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_VERSION_TEXT, strVersion ) )
1620     {
1621         return true; // return error code
1622     }
1623 
1624     // check size: all data is read, the position must now be at the end
1625     if ( iPos != iDataLen )
1626     {
1627         return true; // return error code
1628     }
1629 
1630     // invoke message action
1631     emit VersionAndOSReceived ( eOSType, strVersion );
1632 
1633     return false; // no error
1634 }
1635 
CreateRecorderStateMes(const ERecorderState eRecorderState)1636 void CProtocol::CreateRecorderStateMes ( const ERecorderState eRecorderState )
1637 {
1638     CVector<uint8_t> vecData ( 1 ); // 1 byte of data
1639     int              iPos = 0;      // init position pointer
1640 
1641     // build data vector
1642     // server jam recorder state (1 byte)
1643     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( eRecorderState ), 1 );
1644 
1645     CreateAndSendMessage ( PROTMESSID_RECORDER_STATE, vecData );
1646 }
1647 
EvaluateRecorderStateMes(const CVector<uint8_t> & vecData)1648 bool CProtocol::EvaluateRecorderStateMes ( const CVector<uint8_t>& vecData )
1649 {
1650     int iPos = 0; // init position pointer
1651 
1652     // check size
1653     if ( vecData.Size() != 1 )
1654     {
1655         return true; // return error code
1656     }
1657 
1658     // server jam recorder state (1 byte)
1659     const int iRecorderState = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
1660 
1661     // note that RS_UNDEFINED is only internally used
1662     if ( ( iRecorderState != RS_NOT_INITIALISED ) && ( iRecorderState != RS_NOT_ENABLED ) && ( iRecorderState != RS_RECORDING ) )
1663     {
1664         return true;
1665     }
1666 
1667     // invoke message action
1668     emit RecorderStateReceived ( static_cast<ERecorderState> ( iRecorderState ) );
1669 
1670     return false; // no error
1671 }
1672 
1673 // Connection less messages ----------------------------------------------------
CreateCLPingMes(const CHostAddress & InetAddr,const int iMs)1674 void CProtocol::CreateCLPingMes ( const CHostAddress& InetAddr, const int iMs )
1675 {
1676     int iPos = 0; // init position pointer
1677 
1678     // build data vector (4 bytes long)
1679     CVector<uint8_t> vecData ( 4 );
1680 
1681     // transmit time (4 bytes)
1682     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iMs ), 4 );
1683 
1684     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_PING_MS, vecData, InetAddr );
1685 }
1686 
EvaluateCLPingMes(const CHostAddress & InetAddr,const CVector<uint8_t> & vecData)1687 bool CProtocol::EvaluateCLPingMes ( const CHostAddress& InetAddr, const CVector<uint8_t>& vecData )
1688 {
1689     int iPos = 0; // init position pointer
1690 
1691     // check size
1692     if ( vecData.Size() != 4 )
1693     {
1694         return true; // return error code
1695     }
1696 
1697     // invoke message action
1698     emit CLPingReceived ( InetAddr, static_cast<int> ( GetValFromStream ( vecData, iPos, 4 ) ) );
1699 
1700     return false; // no error
1701 }
1702 
CreateCLPingWithNumClientsMes(const CHostAddress & InetAddr,const int iMs,const int iNumClients)1703 void CProtocol::CreateCLPingWithNumClientsMes ( const CHostAddress& InetAddr, const int iMs, const int iNumClients )
1704 {
1705     int iPos = 0; // init position pointer
1706 
1707     // build data vector (5 bytes long)
1708     CVector<uint8_t> vecData ( 5 );
1709 
1710     // transmit time (4 bytes)
1711     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iMs ), 4 );
1712 
1713     // current number of connected clients (1 byte)
1714     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iNumClients ), 1 );
1715 
1716     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_PING_MS_WITHNUMCLIENTS, vecData, InetAddr );
1717 }
1718 
EvaluateCLPingWithNumClientsMes(const CHostAddress & InetAddr,const CVector<uint8_t> & vecData)1719 bool CProtocol::EvaluateCLPingWithNumClientsMes ( const CHostAddress& InetAddr, const CVector<uint8_t>& vecData )
1720 {
1721     int iPos = 0; // init position pointer
1722 
1723     // check size
1724     if ( vecData.Size() != 5 )
1725     {
1726         return true; // return error code
1727     }
1728 
1729     // transmit time
1730     const int iCurMs = static_cast<int> ( GetValFromStream ( vecData, iPos, 4 ) );
1731 
1732     // current number of connected clients
1733     const int iCurNumClients = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
1734 
1735     // invoke message action
1736     emit CLPingWithNumClientsReceived ( InetAddr, iCurMs, iCurNumClients );
1737 
1738     return false; // no error
1739 }
1740 
CreateCLServerFullMes(const CHostAddress & InetAddr)1741 void CProtocol::CreateCLServerFullMes ( const CHostAddress& InetAddr )
1742 {
1743     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_SERVER_FULL, CVector<uint8_t> ( 0 ), InetAddr );
1744 }
1745 
EvaluateCLServerFullMes()1746 bool CProtocol::EvaluateCLServerFullMes()
1747 {
1748     // invoke message action
1749     emit ServerFullMesReceived();
1750 
1751     return false; // no error
1752 }
1753 
CreateCLRegisterServerMes(const CHostAddress & InetAddr,const CHostAddress & LInetAddr,const CServerCoreInfo & ServerInfo)1754 void CProtocol::CreateCLRegisterServerMes ( const CHostAddress& InetAddr, const CHostAddress& LInetAddr, const CServerCoreInfo& ServerInfo )
1755 {
1756     int iPos = 0; // init position pointer
1757 
1758     // convert server info strings to utf-8
1759     const QByteArray strUTF8LInetAddr = LInetAddr.InetAddr.toString().toUtf8();
1760     const QByteArray strUTF8Name      = ServerInfo.strName.toUtf8();
1761     const QByteArray strUTF8City      = ServerInfo.strCity.toUtf8();
1762 
1763     // size of current message body
1764     const int iEntrLen = 2 +                           // server internal port number
1765                          2 +                           // country
1766                          1 +                           // maximum number of connected clients
1767                          1 +                           // is permanent flag
1768                          2 + strUTF8Name.size() +      // name utf-8 str. size / str.
1769                          2 + strUTF8LInetAddr.size() + // server internal address utf-8 str. size / str.
1770                          2 + strUTF8City.size();       // city utf-8 str. size / str.
1771 
1772     // build data vector
1773     CVector<uint8_t> vecData ( iEntrLen );
1774 
1775     // port number (2 bytes)
1776     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( LInetAddr.iPort ), 2 );
1777 
1778     // country (2 bytes)
1779     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( ServerInfo.eCountry ), 2 );
1780 
1781     // maximum number of connected clients (1 byte)
1782     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( ServerInfo.iMaxNumClients ), 1 );
1783 
1784     // "is permanent" flag (1 byte)
1785     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( ServerInfo.bPermanentOnline ), 1 );
1786 
1787     // name
1788     PutStringUTF8OnStream ( vecData, iPos, strUTF8Name );
1789 
1790     // server internal address (formerly unused topic)
1791     PutStringUTF8OnStream ( vecData, iPos, strUTF8LInetAddr );
1792 
1793     // city
1794     PutStringUTF8OnStream ( vecData, iPos, strUTF8City );
1795 
1796     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REGISTER_SERVER, vecData, InetAddr );
1797 }
1798 
EvaluateCLRegisterServerMes(const CHostAddress & InetAddr,const CVector<uint8_t> & vecData)1799 bool CProtocol::EvaluateCLRegisterServerMes ( const CHostAddress& InetAddr, const CVector<uint8_t>& vecData )
1800 {
1801     int             iPos     = 0; // init position pointer
1802     const int       iDataLen = vecData.Size();
1803     QString         sLocHost; // temp string for server internal address
1804     CHostAddress    LInetAddr;
1805     CServerCoreInfo RecServerInfo;
1806 
1807     // check size (the first 6 bytes)
1808     if ( iDataLen < 6 )
1809     {
1810         return true; // return error code
1811     }
1812 
1813     // port number (2 bytes)
1814     LInetAddr.iPort = static_cast<quint16> ( GetValFromStream ( vecData, iPos, 2 ) );
1815 
1816     // country (2 bytes)
1817     RecServerInfo.eCountry = static_cast<QLocale::Country> ( GetValFromStream ( vecData, iPos, 2 ) );
1818 
1819     // maximum number of connected clients (1 byte)
1820     RecServerInfo.iMaxNumClients = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
1821 
1822     // "is permanent" flag (1 byte)
1823     RecServerInfo.bPermanentOnline = static_cast<bool> ( GetValFromStream ( vecData, iPos, 1 ) );
1824 
1825     // server name
1826     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_SERVER_NAME, RecServerInfo.strName ) )
1827     {
1828         return true; // return error code
1829     }
1830 
1831     // server internal address
1832     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_IP_ADDRESS, sLocHost ) )
1833     {
1834         return true; // return error code
1835     }
1836 
1837     if ( sLocHost.isEmpty() )
1838     {
1839         // old server, empty "topic", register as local host
1840         LInetAddr.InetAddr.setAddress ( QHostAddress::LocalHost );
1841     }
1842     else if ( !LInetAddr.InetAddr.setAddress ( sLocHost ) )
1843     {
1844         return true; // return error code
1845     }
1846 
1847     // server city
1848     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_SERVER_CITY, RecServerInfo.strCity ) )
1849     {
1850         return true; // return error code
1851     }
1852 
1853     // check size: all data is read, the position must now be at the end
1854     if ( iPos != iDataLen )
1855     {
1856         return true; // return error code
1857     }
1858 
1859     // invoke message action
1860     emit CLRegisterServerReceived ( InetAddr, LInetAddr, RecServerInfo );
1861 
1862     return false; // no error
1863 }
1864 
CreateCLRegisterServerExMes(const CHostAddress & InetAddr,const CHostAddress & LInetAddr,const CServerCoreInfo & ServerInfo)1865 void CProtocol::CreateCLRegisterServerExMes ( const CHostAddress& InetAddr, const CHostAddress& LInetAddr, const CServerCoreInfo& ServerInfo )
1866 {
1867     int iPos = 0; // init position pointer
1868 
1869     // convert server info strings to utf-8
1870     const QByteArray strUTF8LInetAddr = LInetAddr.InetAddr.toString().toUtf8();
1871     const QByteArray strUTF8Name      = ServerInfo.strName.toUtf8();
1872     const QByteArray strUTF8City      = ServerInfo.strCity.toUtf8();
1873     const QByteArray strUTF8Version   = QString ( VERSION ).toUtf8();
1874 
1875     // size of current message body
1876     const int iEntrLen = 2 +                           // server internal port number
1877                          2 +                           // country
1878                          1 +                           // maximum number of connected clients
1879                          1 +                           // is permanent flag
1880                          2 + strUTF8Name.size() +      // name utf-8 str. size / str.
1881                          2 + strUTF8LInetAddr.size() + // server internal address utf-8 str. size / str.
1882                          2 + strUTF8City.size() +      // city utf-8 str. size / str.
1883                          1 +                           // operating system
1884                          2 + strUTF8Version.size();    // version utf-8 str. size / str.
1885 
1886     // build data vector
1887     CVector<uint8_t> vecData ( iEntrLen );
1888 
1889     // port number (2 bytes)
1890     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( LInetAddr.iPort ), 2 );
1891 
1892     // country (2 bytes)
1893     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( ServerInfo.eCountry ), 2 );
1894 
1895     // maximum number of connected clients (1 byte)
1896     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( ServerInfo.iMaxNumClients ), 1 );
1897 
1898     // "is permanent" flag (1 byte)
1899     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( ServerInfo.bPermanentOnline ), 1 );
1900 
1901     // name
1902     PutStringUTF8OnStream ( vecData, iPos, strUTF8Name );
1903 
1904     // server internal address (formerly unused topic)
1905     PutStringUTF8OnStream ( vecData, iPos, strUTF8LInetAddr );
1906 
1907     // city
1908     PutStringUTF8OnStream ( vecData, iPos, strUTF8City );
1909 
1910     // operating system (1 byte)
1911     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( COSUtil::GetOperatingSystem() ), 1 );
1912 
1913     // version
1914     PutStringUTF8OnStream ( vecData, iPos, strUTF8Version );
1915 
1916     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REGISTER_SERVER_EX, vecData, InetAddr );
1917 }
1918 
EvaluateCLRegisterServerExMes(const CHostAddress & InetAddr,const CVector<uint8_t> & vecData)1919 bool CProtocol::EvaluateCLRegisterServerExMes ( const CHostAddress& InetAddr, const CVector<uint8_t>& vecData )
1920 {
1921     int             iPos     = 0; // init position pointer
1922     const int       iDataLen = vecData.Size();
1923     QString         sLocHost; // temp string for server internal address
1924     CHostAddress    LInetAddr;
1925     CServerCoreInfo RecServerInfo;
1926 
1927     // check size (the first 6 bytes)
1928     if ( iDataLen < 6 )
1929     {
1930         return true; // return error code
1931     }
1932 
1933     // port number (2 bytes)
1934     LInetAddr.iPort = static_cast<quint16> ( GetValFromStream ( vecData, iPos, 2 ) );
1935 
1936     // country (2 bytes)
1937     RecServerInfo.eCountry = static_cast<QLocale::Country> ( GetValFromStream ( vecData, iPos, 2 ) );
1938 
1939     // maximum number of connected clients (1 byte)
1940     RecServerInfo.iMaxNumClients = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
1941 
1942     // "is permanent" flag (1 byte)
1943     RecServerInfo.bPermanentOnline = static_cast<bool> ( GetValFromStream ( vecData, iPos, 1 ) );
1944 
1945     // server name
1946     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_SERVER_NAME, RecServerInfo.strName ) )
1947     {
1948         return true; // return error code
1949     }
1950 
1951     // server internal address
1952     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_IP_ADDRESS, sLocHost ) )
1953     {
1954         return true; // return error code
1955     }
1956 
1957     if ( sLocHost.isEmpty() )
1958     {
1959         // old server, empty "topic", register as local host
1960         LInetAddr.InetAddr.setAddress ( QHostAddress::LocalHost );
1961     }
1962     else if ( !LInetAddr.InetAddr.setAddress ( sLocHost ) )
1963     {
1964         return true; // return error code
1965     }
1966 
1967     // server city
1968     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_SERVER_CITY, RecServerInfo.strCity ) )
1969     {
1970         return true; // return error code
1971     }
1972 
1973     // check size (the next 1 byte)
1974     if ( iDataLen < iPos + 1 )
1975     {
1976         return true; // return error code
1977     }
1978 
1979     // operating system (1 byte)
1980     const COSUtil::EOpSystemType eOSType = static_cast<COSUtil::EOpSystemType> ( GetValFromStream ( vecData, iPos, 1 ) );
1981 
1982     // version text
1983     QString strVersion;
1984     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_VERSION_TEXT, strVersion ) )
1985     {
1986         return true; // return error code
1987     }
1988 
1989     // check size: all data is read, the position must now be at the end
1990     if ( iPos != iDataLen )
1991     {
1992         return true; // return error code
1993     }
1994 
1995     // invoke message action
1996     emit CLRegisterServerExReceived ( InetAddr, LInetAddr, RecServerInfo, eOSType, strVersion );
1997 
1998     return false; // no error
1999 }
2000 
CreateCLUnregisterServerMes(const CHostAddress & InetAddr)2001 void CProtocol::CreateCLUnregisterServerMes ( const CHostAddress& InetAddr )
2002 {
2003     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_UNREGISTER_SERVER, CVector<uint8_t> ( 0 ), InetAddr );
2004 }
2005 
EvaluateCLUnregisterServerMes(const CHostAddress & InetAddr)2006 bool CProtocol::EvaluateCLUnregisterServerMes ( const CHostAddress& InetAddr )
2007 {
2008     // invoke message action
2009     emit CLUnregisterServerReceived ( InetAddr );
2010 
2011     return false; // no error
2012 }
2013 
CreateCLServerListMes(const CHostAddress & InetAddr,const CVector<CServerInfo> vecServerInfo)2014 void CProtocol::CreateCLServerListMes ( const CHostAddress& InetAddr, const CVector<CServerInfo> vecServerInfo )
2015 {
2016     const int iNumServers = vecServerInfo.Size();
2017 
2018     // build data vector
2019     CVector<uint8_t> vecData ( 0 );
2020     int              iPos = 0; // init position pointer
2021 
2022     for ( int i = 0; i < iNumServers; i++ )
2023     {
2024         // convert server list strings to utf-8
2025         const QByteArray strUTF8Name  = vecServerInfo[i].strName.toUtf8();
2026         const QByteArray strUTF8Empty = QString ( "" ).toUtf8();
2027         const QByteArray strUTF8City  = vecServerInfo[i].strCity.toUtf8();
2028 
2029         // size of current list entry
2030         const int iCurListEntrLen = 4 +                      // IP address
2031                                     2 +                      // port number
2032                                     2 +                      // country
2033                                     1 +                      // maximum number of connected clients
2034                                     1 +                      // is permanent flag
2035                                     2 + strUTF8Name.size() + // name utf-8 str. size / str.
2036                                     2 +                      // empty string
2037                                     2 + strUTF8City.size();  // city utf-8 str. size / str.
2038 
2039         // make space for new data
2040         vecData.Enlarge ( iCurListEntrLen );
2041 
2042         // IP address (4 bytes)
2043         // note the Server List manager has put the internal details in HostAddr where required
2044         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecServerInfo[i].HostAddr.InetAddr.toIPv4Address() ), 4 );
2045 
2046         // port number (2 bytes)
2047         // note the Server List manager has put the internal details in HostAddr where required
2048         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecServerInfo[i].HostAddr.iPort ), 2 );
2049 
2050         // country (2 bytes)
2051         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecServerInfo[i].eCountry ), 2 );
2052 
2053         // maximum number of connected clients (1 byte)
2054         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecServerInfo[i].iMaxNumClients ), 1 );
2055 
2056         // "is permanent" flag (1 byte)
2057         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecServerInfo[i].bPermanentOnline ), 1 );
2058 
2059         // name
2060         PutStringUTF8OnStream ( vecData, iPos, strUTF8Name );
2061 
2062         // empty string
2063         PutStringUTF8OnStream ( vecData, iPos, strUTF8Empty );
2064 
2065         // city
2066         PutStringUTF8OnStream ( vecData, iPos, strUTF8City );
2067     }
2068 
2069     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_SERVER_LIST, vecData, InetAddr );
2070 }
2071 
EvaluateCLServerListMes(const CHostAddress & InetAddr,const CVector<uint8_t> & vecData)2072 bool CProtocol::EvaluateCLServerListMes ( const CHostAddress& InetAddr, const CVector<uint8_t>& vecData )
2073 {
2074     int                  iPos     = 0; // init position pointer
2075     const int            iDataLen = vecData.Size();
2076     CVector<CServerInfo> vecServerInfo ( 0 );
2077 
2078     while ( iPos < iDataLen )
2079     {
2080         // check size (the next 10 bytes)
2081         if ( ( iDataLen - iPos ) < 10 )
2082         {
2083             return true; // return error code
2084         }
2085 
2086         // IP address (4 bytes)
2087         const quint32 iIpAddr = static_cast<quint32> ( GetValFromStream ( vecData, iPos, 4 ) );
2088 
2089         // port number (2 bytes)
2090         const quint16 iPort = static_cast<quint16> ( GetValFromStream ( vecData, iPos, 2 ) );
2091 
2092         // country (2 bytes)
2093         const QLocale::Country eCountry = static_cast<QLocale::Country> ( GetValFromStream ( vecData, iPos, 2 ) );
2094 
2095         // maximum number of connected clients (1 byte)
2096         const int iMaxNumClients = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
2097 
2098         // "is permanent" flag (1 byte)
2099         const bool bPermanentOnline = static_cast<bool> ( GetValFromStream ( vecData, iPos, 1 ) );
2100 
2101         // server name
2102         QString strName;
2103         if ( GetStringFromStream ( vecData, iPos, MAX_LEN_SERVER_NAME, strName ) )
2104         {
2105             return true; // return error code
2106         }
2107 
2108         // empty
2109         QString strEmpty;
2110         if ( GetStringFromStream ( vecData, iPos, MAX_LEN_IP_ADDRESS, strEmpty ) )
2111         {
2112             return true; // return error code
2113         }
2114 
2115         // server city
2116         QString strCity;
2117         if ( GetStringFromStream ( vecData, iPos, MAX_LEN_SERVER_CITY, strCity ) )
2118         {
2119             return true; // return error code
2120         }
2121 
2122         // add server information to vector
2123         vecServerInfo.Add ( CServerInfo ( CHostAddress ( QHostAddress ( iIpAddr ), iPort ),
2124                                           CHostAddress ( QHostAddress ( iIpAddr ), iPort ),
2125                                           strName,
2126                                           eCountry,
2127                                           strCity,
2128                                           iMaxNumClients,
2129                                           bPermanentOnline ) );
2130     }
2131 
2132     // check size: all data is read, the position must now be at the end
2133     if ( iPos != iDataLen )
2134     {
2135         return true; // return error code
2136     }
2137 
2138     // invoke message action
2139     emit CLServerListReceived ( InetAddr, vecServerInfo );
2140 
2141     return false; // no error
2142 }
2143 
CreateCLRedServerListMes(const CHostAddress & InetAddr,const CVector<CServerInfo> vecServerInfo)2144 void CProtocol::CreateCLRedServerListMes ( const CHostAddress& InetAddr, const CVector<CServerInfo> vecServerInfo )
2145 {
2146     const int iNumServers = vecServerInfo.Size();
2147 
2148     // build data vector
2149     CVector<uint8_t> vecData ( 0 );
2150     int              iPos = 0; // init position pointer
2151 
2152     for ( int i = 0; i < iNumServers; i++ )
2153     {
2154         // convert server list strings to utf-8
2155         const QByteArray strUTF8Name = vecServerInfo[i].strName.toUtf8();
2156 
2157         // size of current list entry
2158         const int iCurListEntrLen = 4 +                     // IP address
2159                                     2 +                     // port number
2160                                     1 + strUTF8Name.size(); // name utf-8 str. size / str.
2161 
2162         // make space for new data
2163         vecData.Enlarge ( iCurListEntrLen );
2164 
2165         // IP address (4 bytes)
2166         // note the Server List manager has put the internal details in HostAddr where required
2167         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecServerInfo[i].HostAddr.InetAddr.toIPv4Address() ), 4 );
2168 
2169         // port number (2 bytes)
2170         // note the Server List manager has put the internal details in HostAddr where required
2171         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecServerInfo[i].HostAddr.iPort ), 2 );
2172 
2173         // name (note that the string length indicator is 1 in this special case)
2174         PutStringUTF8OnStream ( vecData, iPos, strUTF8Name, 1 );
2175     }
2176 
2177     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_RED_SERVER_LIST, vecData, InetAddr );
2178 }
2179 
EvaluateCLRedServerListMes(const CHostAddress & InetAddr,const CVector<uint8_t> & vecData)2180 bool CProtocol::EvaluateCLRedServerListMes ( const CHostAddress& InetAddr, const CVector<uint8_t>& vecData )
2181 {
2182     int                  iPos     = 0; // init position pointer
2183     const int            iDataLen = vecData.Size();
2184     CVector<CServerInfo> vecServerInfo ( 0 );
2185 
2186     while ( iPos < iDataLen )
2187     {
2188         // check size (the next 6 bytes)
2189         if ( ( iDataLen - iPos ) < 6 )
2190         {
2191             return true; // return error code
2192         }
2193 
2194         // IP address (4 bytes)
2195         const quint32 iIpAddr = static_cast<quint32> ( GetValFromStream ( vecData, iPos, 4 ) );
2196 
2197         // port number (2 bytes)
2198         const quint16 iPort = static_cast<quint16> ( GetValFromStream ( vecData, iPos, 2 ) );
2199 
2200         // server name (note that the string length indicator is 1 in this special case)
2201         QString strName;
2202         if ( GetStringFromStream ( vecData, iPos, MAX_LEN_SERVER_NAME, strName, 1 ) )
2203         {
2204             return true; // return error code
2205         }
2206 
2207         // add server information to vector
2208         vecServerInfo.Add ( CServerInfo ( CHostAddress ( QHostAddress ( iIpAddr ), iPort ),
2209                                           CHostAddress ( QHostAddress ( iIpAddr ), iPort ),
2210                                           strName,
2211                                           QLocale::AnyCountry, // set to any country since the information is not transmitted
2212                                           "",                  // empty city name since the information is not transmitted
2213                                           0,                   // per definition: if max. num. client is zero, we ignore the value in the server list
2214                                           false ) );           // assume not permanent since the information is not transmitted
2215     }
2216 
2217     // check size: all data is read, the position must now be at the end
2218     if ( iPos != iDataLen )
2219     {
2220         return true; // return error code
2221     }
2222 
2223     // invoke message action
2224     emit CLRedServerListReceived ( InetAddr, vecServerInfo );
2225 
2226     return false; // no error
2227 }
2228 
CreateCLReqServerListMes(const CHostAddress & InetAddr)2229 void CProtocol::CreateCLReqServerListMes ( const CHostAddress& InetAddr )
2230 {
2231     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REQ_SERVER_LIST, CVector<uint8_t> ( 0 ), InetAddr );
2232 }
2233 
EvaluateCLReqServerListMes(const CHostAddress & InetAddr)2234 bool CProtocol::EvaluateCLReqServerListMes ( const CHostAddress& InetAddr )
2235 {
2236     // invoke message action
2237     emit CLReqServerList ( InetAddr );
2238 
2239     return false; // no error
2240 }
2241 
CreateCLSendEmptyMesMes(const CHostAddress & InetAddr,const CHostAddress & TargetInetAddr)2242 void CProtocol::CreateCLSendEmptyMesMes ( const CHostAddress& InetAddr, const CHostAddress& TargetInetAddr )
2243 {
2244     int iPos = 0; // init position pointer
2245 
2246     // build data vector (6 bytes long)
2247     CVector<uint8_t> vecData ( 6 );
2248 
2249     // IP address (4 bytes)
2250     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( TargetInetAddr.InetAddr.toIPv4Address() ), 4 );
2251 
2252     // port number (2 bytes)
2253     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( TargetInetAddr.iPort ), 2 );
2254 
2255     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_SEND_EMPTY_MESSAGE, vecData, InetAddr );
2256 }
2257 
EvaluateCLSendEmptyMesMes(const CVector<uint8_t> & vecData)2258 bool CProtocol::EvaluateCLSendEmptyMesMes ( const CVector<uint8_t>& vecData )
2259 {
2260     int iPos = 0; // init position pointer
2261 
2262     // check size
2263     if ( vecData.Size() != 6 )
2264     {
2265         return true; // return error code
2266     }
2267 
2268     // IP address (4 bytes)
2269     const quint32 iIpAddr = static_cast<int> ( GetValFromStream ( vecData, iPos, 4 ) );
2270 
2271     // port number (2 bytes)
2272     const quint16 iPort = static_cast<int> ( GetValFromStream ( vecData, iPos, 2 ) );
2273 
2274     // invoke message action
2275     emit CLSendEmptyMes ( CHostAddress ( QHostAddress ( iIpAddr ), iPort ) );
2276 
2277     return false; // no error
2278 }
2279 
CreateCLEmptyMes(const CHostAddress & InetAddr)2280 void CProtocol::CreateCLEmptyMes ( const CHostAddress& InetAddr )
2281 {
2282     // special message: for this message there exist no Evaluate
2283     // function
2284     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_EMPTY_MESSAGE, CVector<uint8_t> ( 0 ), InetAddr );
2285 }
2286 
CreateCLDisconnection(const CHostAddress & InetAddr)2287 void CProtocol::CreateCLDisconnection ( const CHostAddress& InetAddr )
2288 {
2289     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_DISCONNECTION, CVector<uint8_t> ( 0 ), InetAddr );
2290 }
2291 
EvaluateCLDisconnectionMes(const CHostAddress & InetAddr)2292 bool CProtocol::EvaluateCLDisconnectionMes ( const CHostAddress& InetAddr )
2293 {
2294     // invoke message action
2295     emit CLDisconnection ( InetAddr );
2296 
2297     return false; // no error
2298 }
2299 
CreateCLVersionAndOSMes(const CHostAddress & InetAddr)2300 void CProtocol::CreateCLVersionAndOSMes ( const CHostAddress& InetAddr )
2301 {
2302     int iPos = 0; // init position pointer
2303 
2304     // get the version number string
2305     const QString strVerion = VERSION;
2306 
2307     // convert version string to utf-8
2308     const QByteArray strUTF8Version = strVerion.toUtf8();
2309 
2310     // size of current message body
2311     const int iEntrLen = 1 +                        // operating system
2312                          2 + strUTF8Version.size(); // version utf-8 str. size / str.
2313 
2314     // build data vector
2315     CVector<uint8_t> vecData ( iEntrLen );
2316 
2317     // operating system (1 byte)
2318     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( COSUtil::GetOperatingSystem() ), 1 );
2319 
2320     // version
2321     PutStringUTF8OnStream ( vecData, iPos, strUTF8Version );
2322 
2323     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_VERSION_AND_OS, vecData, InetAddr );
2324 }
2325 
EvaluateCLVersionAndOSMes(const CHostAddress & InetAddr,const CVector<uint8_t> & vecData)2326 bool CProtocol::EvaluateCLVersionAndOSMes ( const CHostAddress& InetAddr, const CVector<uint8_t>& vecData )
2327 {
2328     int       iPos     = 0; // init position pointer
2329     const int iDataLen = vecData.Size();
2330 
2331     // check size (the first 1 byte)
2332     if ( iDataLen < 1 )
2333     {
2334         return true; // return error code
2335     }
2336 
2337     // operating system (1 byte)
2338     const COSUtil::EOpSystemType eOSType = static_cast<COSUtil::EOpSystemType> ( GetValFromStream ( vecData, iPos, 1 ) );
2339 
2340     // version text
2341     QString strVersion;
2342     if ( GetStringFromStream ( vecData, iPos, MAX_LEN_VERSION_TEXT, strVersion ) )
2343     {
2344         return true; // return error code
2345     }
2346 
2347     // check size: all data is read, the position must now be at the end
2348     if ( iPos != iDataLen )
2349     {
2350         return true; // return error code
2351     }
2352 
2353     // invoke message action
2354     emit CLVersionAndOSReceived ( InetAddr, eOSType, strVersion );
2355 
2356     return false; // no error
2357 }
2358 
CreateCLReqVersionAndOSMes(const CHostAddress & InetAddr)2359 void CProtocol::CreateCLReqVersionAndOSMes ( const CHostAddress& InetAddr )
2360 {
2361     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REQ_VERSION_AND_OS, CVector<uint8_t> ( 0 ), InetAddr );
2362 }
2363 
EvaluateCLReqVersionAndOSMes(const CHostAddress & InetAddr)2364 bool CProtocol::EvaluateCLReqVersionAndOSMes ( const CHostAddress& InetAddr )
2365 {
2366     // invoke message action
2367     emit CLReqVersionAndOS ( InetAddr );
2368 
2369     return false; // no error
2370 }
2371 
CreateCLConnClientsListMes(const CHostAddress & InetAddr,const CVector<CChannelInfo> & vecChanInfo)2372 void CProtocol::CreateCLConnClientsListMes ( const CHostAddress& InetAddr, const CVector<CChannelInfo>& vecChanInfo )
2373 {
2374     const int iNumClients = vecChanInfo.Size();
2375 
2376     // build data vector
2377     CVector<uint8_t> vecData ( 0 );
2378     int              iPos = 0; // init position pointer
2379 
2380     for ( int i = 0; i < iNumClients; i++ )
2381     {
2382         // convert strings to utf-8
2383         const QByteArray strUTF8Name = vecChanInfo[i].strName.toUtf8();
2384         const QByteArray strUTF8City = vecChanInfo[i].strCity.toUtf8();
2385 
2386         // size of current list entry
2387         const int iCurListEntrLen = 1 +                      // chan ID
2388                                     2 +                      // country
2389                                     4 +                      // instrument
2390                                     1 +                      // skill level
2391                                     4 +                      // IP address
2392                                     2 + strUTF8Name.size() + // utf-8 str. size / str.
2393                                     2 + strUTF8City.size();  // utf-8 str. size / str.
2394 
2395         // make space for new data
2396         vecData.Enlarge ( iCurListEntrLen );
2397 
2398         // channel ID (1 byte)
2399         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecChanInfo[i].iChanID ), 1 );
2400 
2401         // country (2 bytes)
2402         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecChanInfo[i].eCountry ), 2 );
2403 
2404         // instrument (4 bytes)
2405         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecChanInfo[i].iInstrument ), 4 );
2406 
2407         // skill level (1 byte)
2408         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( vecChanInfo[i].eSkillLevel ), 1 );
2409 
2410         // used to be IP address before #316 (4 bytes)
2411         PutValOnStream ( vecData, iPos, 0, 4 );
2412 
2413         // name
2414         PutStringUTF8OnStream ( vecData, iPos, strUTF8Name );
2415 
2416         // city
2417         PutStringUTF8OnStream ( vecData, iPos, strUTF8City );
2418     }
2419 
2420     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_CONN_CLIENTS_LIST, vecData, InetAddr );
2421 }
2422 
EvaluateCLConnClientsListMes(const CHostAddress & InetAddr,const CVector<uint8_t> & vecData)2423 bool CProtocol::EvaluateCLConnClientsListMes ( const CHostAddress& InetAddr, const CVector<uint8_t>& vecData )
2424 {
2425     int                   iPos     = 0; // init position pointer
2426     const int             iDataLen = vecData.Size();
2427     CVector<CChannelInfo> vecChanInfo ( 0 );
2428 
2429     while ( iPos < iDataLen )
2430     {
2431         // check size (the next 12 bytes)
2432         if ( ( iDataLen - iPos ) < 12 )
2433         {
2434             return true; // return error code
2435         }
2436 
2437         // channel ID (1 byte)
2438         const int iChanID = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
2439 
2440         // country (2 bytes)
2441         const QLocale::Country eCountry = static_cast<QLocale::Country> ( GetValFromStream ( vecData, iPos, 2 ) );
2442 
2443         // instrument (4 bytes)
2444         const int iInstrument = static_cast<int> ( GetValFromStream ( vecData, iPos, 4 ) );
2445 
2446         // skill level (1 byte)
2447         const ESkillLevel eSkillLevel = static_cast<ESkillLevel> ( GetValFromStream ( vecData, iPos, 1 ) );
2448 
2449         // used to be IP address, zero since #316 (4 bytes)
2450         iPos += 4;
2451 
2452         // name
2453         QString strCurName;
2454         if ( GetStringFromStream ( vecData, iPos, MAX_LEN_FADER_TAG, strCurName ) )
2455         {
2456             return true; // return error code
2457         }
2458 
2459         // city
2460         QString strCurCity;
2461         if ( GetStringFromStream ( vecData, iPos, MAX_LEN_SERVER_CITY, strCurCity ) )
2462         {
2463             return true; // return error code
2464         }
2465 
2466         // add channel information to vector
2467         vecChanInfo.Add ( CChannelInfo ( iChanID, strCurName, eCountry, strCurCity, iInstrument, eSkillLevel ) );
2468     }
2469 
2470     // check size: all data is read, the position must now be at the end
2471     if ( iPos != iDataLen )
2472     {
2473         return true; // return error code
2474     }
2475 
2476     // invoke message action
2477     emit CLConnClientsListMesReceived ( InetAddr, vecChanInfo );
2478 
2479     return false; // no error
2480 }
2481 
CreateCLReqConnClientsListMes(const CHostAddress & InetAddr)2482 void CProtocol::CreateCLReqConnClientsListMes ( const CHostAddress& InetAddr )
2483 {
2484     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST, CVector<uint8_t> ( 0 ), InetAddr );
2485 }
2486 
EvaluateCLReqConnClientsListMes(const CHostAddress & InetAddr)2487 bool CProtocol::EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr )
2488 {
2489     // invoke message action
2490     emit CLReqConnClientsList ( InetAddr );
2491 
2492     return false; // no error
2493 }
2494 
CreateCLChannelLevelListMes(const CHostAddress & InetAddr,const CVector<uint16_t> & vecLevelList,const int iNumClients)2495 void CProtocol::CreateCLChannelLevelListMes ( const CHostAddress& InetAddr, const CVector<uint16_t>& vecLevelList, const int iNumClients )
2496 {
2497     // This must be a multiple of bytes at four bits per client
2498     const int        iNumBytes = ( iNumClients + 1 ) / 2;
2499     CVector<uint8_t> vecData ( iNumBytes );
2500     int              iPos = 0; // init position pointer
2501 
2502     for ( int i = 0, j = 0; i < iNumClients; i += 2 /* pack two per byte */, j++ )
2503     {
2504         uint16_t levelLo = vecLevelList[i] & 0x0F;
2505         uint16_t levelHi = ( i + 1 < iNumClients ) ? vecLevelList[i + 1] & 0x0F : 0x0F;
2506         uint8_t  byte    = static_cast<uint8_t> ( levelLo | ( levelHi << 4 ) );
2507 
2508         PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( byte ), 1 );
2509     }
2510 
2511     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_CHANNEL_LEVEL_LIST, vecData, InetAddr );
2512 }
2513 
EvaluateCLChannelLevelListMes(const CHostAddress & InetAddr,const CVector<uint8_t> & vecData)2514 bool CProtocol::EvaluateCLChannelLevelListMes ( const CHostAddress& InetAddr, const CVector<uint8_t>& vecData )
2515 {
2516     int       iPos     = 0;              // init position pointer
2517     const int iDataLen = vecData.Size(); // four bits per channel, 2 channels per byte
2518                                          // may have one too many entries, last being 0xF
2519     int iVecLen = iDataLen * 2;          // one ushort per channel
2520 
2521     if ( iVecLen > MAX_NUM_CHANNELS )
2522     {
2523         return true; // return error code
2524     }
2525 
2526     CVector<uint16_t> vecLevelList ( iVecLen );
2527 
2528     for ( int i = 0, j = 0; i < iDataLen; i++, j += 2 )
2529     {
2530         uint8_t  byte    = static_cast<uint8_t> ( GetValFromStream ( vecData, iPos, 1 ) );
2531         uint16_t levelLo = byte & 0x0F;
2532         uint16_t levelHi = ( byte >> 4 ) & 0x0F;
2533 
2534         vecLevelList[j] = levelLo;
2535 
2536         if ( levelHi != 0x0F )
2537         {
2538             vecLevelList[j + 1] = levelHi;
2539         }
2540         else
2541         {
2542             vecLevelList.resize ( iVecLen - 1 );
2543             break;
2544         }
2545     }
2546 
2547     // invoke message action
2548     emit CLChannelLevelListReceived ( InetAddr, vecLevelList );
2549 
2550     return false; // no error
2551 }
2552 
CreateCLRegisterServerResp(const CHostAddress & InetAddr,const ESvrRegResult eResult)2553 void CProtocol::CreateCLRegisterServerResp ( const CHostAddress& InetAddr, const ESvrRegResult eResult )
2554 {
2555     int              iPos = 0; // init position pointer
2556     CVector<uint8_t> vecData ( 1 );
2557 
2558     PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( eResult ), 1 );
2559 
2560     CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REGISTER_SERVER_RESP, vecData, InetAddr );
2561 }
2562 
EvaluateCLRegisterServerResp(const CHostAddress & InetAddr,const CVector<uint8_t> & vecData)2563 bool CProtocol::EvaluateCLRegisterServerResp ( const CHostAddress& InetAddr, const CVector<uint8_t>& vecData )
2564 {
2565     int       iPos     = 0; // init position pointer
2566     const int iDataLen = vecData.Size();
2567 
2568     if ( iDataLen != 1 )
2569     {
2570         return true;
2571     }
2572 
2573     // server registration result (1 byte)
2574     const int iSvrRegResult = static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
2575 
2576     if ( ( iSvrRegResult != SRR_REGISTERED ) && ( iSvrRegResult != SRR_CENTRAL_SVR_FULL ) && ( iSvrRegResult != SRR_VERSION_TOO_OLD ) &&
2577          ( iSvrRegResult != SRR_NOT_FULFILL_REQIREMENTS ) )
2578     {
2579         return true;
2580     }
2581 
2582     // invoke message action
2583     emit CLRegisterServerResp ( InetAddr, static_cast<ESvrRegResult> ( iSvrRegResult ) );
2584 
2585     return false; // no error
2586 }
2587 
2588 /******************************************************************************\
2589 * Message generation and parsing                                               *
2590 \******************************************************************************/
ParseMessageFrame(const CVector<uint8_t> & vecbyData,const int iNumBytesIn,CVector<uint8_t> & vecbyMesBodyData,int & iCnt,int & iID)2591 bool CProtocol::ParseMessageFrame ( const CVector<uint8_t>& vecbyData,
2592                                     const int               iNumBytesIn,
2593                                     CVector<uint8_t>&       vecbyMesBodyData,
2594                                     int&                    iCnt,
2595                                     int&                    iID )
2596 {
2597     int i;
2598     int iCurPos;
2599 
2600     // vector must be at least "MESS_LEN_WITHOUT_DATA_BYTE" bytes long
2601     if ( iNumBytesIn < MESS_LEN_WITHOUT_DATA_BYTE )
2602     {
2603         return true; // return error code
2604     }
2605 
2606     // Decode header -----------------------------------------------------------
2607     iCurPos = 0; // start from beginning
2608 
2609     // 2 bytes TAG
2610     const int iTag = static_cast<int> ( GetValFromStream ( vecbyData, iCurPos, 2 ) );
2611 
2612     // check if tag is correct
2613     if ( iTag != 0 )
2614     {
2615         return true; // return error code
2616     }
2617 
2618     // 2 bytes ID
2619     iID = static_cast<int> ( GetValFromStream ( vecbyData, iCurPos, 2 ) );
2620 
2621     // 1 byte cnt
2622     iCnt = static_cast<int> ( GetValFromStream ( vecbyData, iCurPos, 1 ) );
2623 
2624     // 2 bytes length
2625     const int iLenBy = static_cast<int> ( GetValFromStream ( vecbyData, iCurPos, 2 ) );
2626 
2627     // make sure the length is correct
2628     if ( iLenBy != iNumBytesIn - MESS_LEN_WITHOUT_DATA_BYTE )
2629     {
2630         return true; // return error code
2631     }
2632 
2633     // Now check CRC -----------------------------------------------------------
2634     CCRC CRCObj;
2635 
2636     const int iLenCRCCalc = MESS_HEADER_LENGTH_BYTE + iLenBy;
2637 
2638     iCurPos = 0; // start from the beginning
2639 
2640     for ( i = 0; i < iLenCRCCalc; i++ )
2641     {
2642         CRCObj.AddByte ( static_cast<uint8_t> ( GetValFromStream ( vecbyData, iCurPos, 1 ) ) );
2643     }
2644 
2645     if ( CRCObj.GetCRC() != GetValFromStream ( vecbyData, iCurPos, 2 ) )
2646     {
2647         return true; // return error code
2648     }
2649 
2650     // Extract actual data -----------------------------------------------------
2651 
2652     // clang-format off
2653 // TODO this memory allocation is done in the real time thread but should be
2654 //      done in the low priority protocol management thread
2655     // clang-format on
2656 
2657     vecbyMesBodyData.Init ( iLenBy );
2658 
2659     iCurPos = MESS_HEADER_LENGTH_BYTE; // start from beginning of data
2660 
2661     for ( i = 0; i < iLenBy; i++ )
2662     {
2663         vecbyMesBodyData[i] = static_cast<uint8_t> ( GetValFromStream ( vecbyData, iCurPos, 1 ) );
2664     }
2665 
2666     return false; // no error
2667 }
2668 
ParseSplitMessageContainer(const CVector<uint8_t> & vecbyData,CVector<uint8_t> & vecbyMesBodyData,const int iSplitMessageDataIndex,int & iID,int & iNumParts,int & iSplitCnt,int & iCurPartSize)2669 bool CProtocol::ParseSplitMessageContainer ( const CVector<uint8_t>& vecbyData,
2670                                              CVector<uint8_t>&       vecbyMesBodyData,
2671                                              const int               iSplitMessageDataIndex,
2672                                              int&                    iID,
2673                                              int&                    iNumParts,
2674                                              int&                    iSplitCnt,
2675                                              int&                    iCurPartSize )
2676 {
2677     int       iPos     = 0; // init position pointer
2678     const int iDataLen = vecbyData.Size();
2679 
2680     // check size (the first 4 bytes)
2681     if ( iDataLen < 4 )
2682     {
2683         return true; // return error code
2684     }
2685 
2686     // 2 bytes ID
2687     iID = static_cast<int> ( GetValFromStream ( vecbyData, iPos, 2 ) );
2688 
2689     // 1 byte number of parts
2690     iNumParts = static_cast<int> ( GetValFromStream ( vecbyData, iPos, 1 ) );
2691 
2692     // 1 byte split cnt
2693     iSplitCnt = static_cast<int> ( GetValFromStream ( vecbyData, iPos, 1 ) );
2694 
2695     // Extract actual data -----------------------------------------------------
2696     iCurPartSize = iDataLen - 4;
2697 
2698     // the memory must be allocated outside this function -> check the size
2699     if ( vecbyMesBodyData.Size() < iSplitMessageDataIndex + iCurPartSize )
2700     {
2701         return true; // return error code
2702     }
2703 
2704     for ( int i = 0; i < iCurPartSize; i++ )
2705     {
2706         vecbyMesBodyData[iSplitMessageDataIndex + i] = static_cast<uint8_t> ( GetValFromStream ( vecbyData, iPos, 1 ) );
2707     }
2708 
2709     return false; // no error
2710 }
2711 
GetValFromStream(const CVector<uint8_t> & vecIn,int & iPos,const int iNumOfBytes)2712 uint32_t CProtocol::GetValFromStream ( const CVector<uint8_t>& vecIn, int& iPos, const int iNumOfBytes )
2713 {
2714     /*
2715         note: iPos is automatically incremented in this function
2716     */
2717     // 4 bytes maximum since we return uint32
2718     Q_ASSERT ( ( iNumOfBytes > 0 ) && ( iNumOfBytes <= 4 ) );
2719     Q_ASSERT ( vecIn.Size() >= iPos + iNumOfBytes );
2720 
2721     uint32_t iRet = 0;
2722 
2723     for ( int i = 0; i < iNumOfBytes; i++ )
2724     {
2725         iRet |= vecIn[iPos] << ( i * 8 /* size of byte */ );
2726         iPos++;
2727     }
2728 
2729     return iRet;
2730 }
2731 
GetStringFromStream(const CVector<uint8_t> & vecIn,int & iPos,const int iMaxStringLen,QString & strOut,const int iNumberOfBytsLen)2732 bool CProtocol::GetStringFromStream ( const CVector<uint8_t>& vecIn, int& iPos, const int iMaxStringLen, QString& strOut, const int iNumberOfBytsLen )
2733 {
2734     /*
2735         note: iPos is automatically incremented in this function
2736     */
2737     const int iInLen = vecIn.Size();
2738 
2739     // check if at least iNumberOfBytsLen bytes are available
2740     if ( ( iInLen - iPos ) < iNumberOfBytsLen )
2741     {
2742         return true; // return error code
2743     }
2744 
2745     // number of bytes for utf-8 string (1 or 2 bytes)
2746     const int iStrUTF8Len = static_cast<int> ( GetValFromStream ( vecIn, iPos, iNumberOfBytsLen ) );
2747 
2748     // (note that iPos was incremented by 2 in the above code!)
2749     if ( ( iInLen - iPos ) < iStrUTF8Len )
2750     {
2751         return true; // return error code
2752     }
2753 
2754     // string (n bytes)
2755     QByteArray sStringUTF8;
2756 
2757     for ( int i = 0; i < iStrUTF8Len; i++ )
2758     {
2759         // byte-by-byte copying of the string data
2760         sStringUTF8.append ( static_cast<char> ( GetValFromStream ( vecIn, iPos, 1 ) ) );
2761     }
2762 
2763     // convert utf-8 byte array in the return string
2764     strOut = QString::fromUtf8 ( sStringUTF8 );
2765 
2766     // check length of actual string
2767     if ( strOut.size() > iMaxStringLen )
2768     {
2769         return true; // return error code
2770     }
2771 
2772     return false; // no error
2773 }
2774 
GenMessageFrame(CVector<uint8_t> & vecOut,const int iCnt,const int iID,const CVector<uint8_t> & vecData)2775 void CProtocol::GenMessageFrame ( CVector<uint8_t>& vecOut, const int iCnt, const int iID, const CVector<uint8_t>& vecData )
2776 {
2777     int i;
2778 
2779     // query length of data vector
2780     const int iDataLenByte = vecData.Size();
2781 
2782     // total length of message
2783     const int iTotLenByte = MESS_LEN_WITHOUT_DATA_BYTE + iDataLenByte;
2784 
2785     // init message vector
2786     vecOut.Init ( iTotLenByte );
2787 
2788     // Encode header -----------------------------------------------------------
2789     int iCurPos = 0; // init position pointer
2790 
2791     // 2 bytes TAG (all zero bits)
2792     PutValOnStream ( vecOut, iCurPos, static_cast<uint32_t> ( 0 ), 2 );
2793 
2794     // 2 bytes ID
2795     PutValOnStream ( vecOut, iCurPos, static_cast<uint32_t> ( iID ), 2 );
2796 
2797     // 1 byte cnt
2798     PutValOnStream ( vecOut, iCurPos, static_cast<uint32_t> ( iCnt ), 1 );
2799 
2800     // 2 bytes length
2801     PutValOnStream ( vecOut, iCurPos, static_cast<uint32_t> ( iDataLenByte ), 2 );
2802 
2803     // encode data -----
2804     for ( i = 0; i < iDataLenByte; i++ )
2805     {
2806         PutValOnStream ( vecOut, iCurPos, static_cast<uint32_t> ( vecData[i] ), 1 );
2807     }
2808 
2809     // Encode CRC --------------------------------------------------------------
2810     CCRC CRCObj;
2811 
2812     iCurPos = 0; // start from beginning
2813 
2814     const int iLenCRCCalc = MESS_HEADER_LENGTH_BYTE + iDataLenByte;
2815 
2816     for ( i = 0; i < iLenCRCCalc; i++ )
2817     {
2818         CRCObj.AddByte ( static_cast<uint8_t> ( GetValFromStream ( vecOut, iCurPos, 1 ) ) );
2819     }
2820 
2821     PutValOnStream ( vecOut, iCurPos, static_cast<uint32_t> ( CRCObj.GetCRC() ), 2 );
2822 }
2823 
GenSplitMessageContainer(CVector<uint8_t> & vecOut,const int iID,const int iNumParts,const int iSplitCnt,const CVector<uint8_t> & vecData,const int iStartIndexInData,const int iLengthOfDataPart)2824 void CProtocol::GenSplitMessageContainer ( CVector<uint8_t>&       vecOut,
2825                                            const int               iID,
2826                                            const int               iNumParts,
2827                                            const int               iSplitCnt,
2828                                            const CVector<uint8_t>& vecData,
2829                                            const int               iStartIndexInData,
2830                                            const int               iLengthOfDataPart )
2831 {
2832     int iPos = 0; // init position pointer
2833 
2834     // total length of message
2835     const int iTotLenByte = 4 + iLengthOfDataPart;
2836 
2837     // init message vector
2838     vecOut.Init ( iTotLenByte );
2839 
2840     // 2 bytes ID
2841     PutValOnStream ( vecOut, iPos, static_cast<uint32_t> ( iID ), 2 );
2842 
2843     // 1 byte number of parts
2844     PutValOnStream ( vecOut, iPos, static_cast<uint32_t> ( iNumParts ), 1 );
2845 
2846     // 1 byte split cnt
2847     PutValOnStream ( vecOut, iPos, static_cast<uint32_t> ( iSplitCnt ), 1 );
2848 
2849     // data
2850     for ( int i = 0; i < iLengthOfDataPart; i++ )
2851     {
2852         PutValOnStream ( vecOut, iPos, static_cast<uint32_t> ( vecData[iStartIndexInData + i] ), 1 );
2853     }
2854 }
2855 
PutValOnStream(CVector<uint8_t> & vecIn,int & iPos,const uint32_t iVal,const int iNumOfBytes)2856 void CProtocol::PutValOnStream ( CVector<uint8_t>& vecIn, int& iPos, const uint32_t iVal, const int iNumOfBytes )
2857 {
2858     /*
2859         note: iPos is automatically incremented in this function
2860     */
2861     // 4 bytes maximum since we use uint32
2862     Q_ASSERT ( ( iNumOfBytes > 0 ) && ( iNumOfBytes <= 4 ) );
2863     Q_ASSERT ( vecIn.Size() >= iPos + iNumOfBytes );
2864 
2865     for ( int i = 0; i < iNumOfBytes; i++ )
2866     {
2867         vecIn[iPos] = ( iVal >> ( i * 8 /* size of byte */ ) ) & 255 /* 11111111 */;
2868         iPos++;
2869     }
2870 }
2871 
PutStringUTF8OnStream(CVector<uint8_t> & vecIn,int & iPos,const QByteArray & sStringUTF8,const int iNumberOfBytsLen)2872 void CProtocol::PutStringUTF8OnStream ( CVector<uint8_t>& vecIn, int& iPos, const QByteArray& sStringUTF8, const int iNumberOfBytsLen )
2873 {
2874     // get the utf-8 string size
2875     const int iStrUTF8Len = sStringUTF8.size();
2876 
2877     // number of bytes for utf-8 string (iNumberOfBytsLen bytes)
2878     PutValOnStream ( vecIn, iPos, static_cast<uint32_t> ( iStrUTF8Len ), iNumberOfBytsLen );
2879 
2880     // actual utf-8 string (n bytes)
2881     for ( int j = 0; j < iStrUTF8Len; j++ )
2882     {
2883         // byte-by-byte copying of the utf-8 string data
2884         PutValOnStream ( vecIn, iPos, static_cast<uint32_t> ( sStringUTF8[j] ), 1 );
2885     }
2886 }
2887