1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: net_packet.cpp 4430 2013-12-15 01:34:36Z russellrice $
5 //
6 // Copyright (C) 2006-2012 by The Odamex Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 // DESCRIPTION:
19 // Launcher packet structure file
20 //
21 // AUTHORS:
22 // Russell Rice (russell at odamex dot net)
23 // Michael Wood (mwoodj at huntsvegas dot org)
24 //
25 //-----------------------------------------------------------------------------
26
27 #include <iostream>
28 #include <sstream>
29 #include <cstdlib>
30
31 #include "net_packet.h"
32 #include "net_error.h"
33 //#include "net_cvartable.h"
34
35 using namespace std;
36
37 namespace odalpapi {
38
39 /*
40 Create a packet to send, which in turn will
41 receive data from the server
42
43 NOTE: All packet classes derive from this, so if some
44 packets require different data, you'll have
45 to override this
46 */
Query(int32_t Timeout)47 int32_t ServerBase::Query(int32_t Timeout)
48 {
49 int8_t Retry = m_RetryCount;
50
51 if (m_Address.empty() || !m_Port)
52 return 0;
53
54 Socket->SetRemoteAddress(m_Address, m_Port);
55
56 Socket->ClearBuffer();
57
58 // If we didn't get it the first time, try again
59 while (Retry)
60 {
61 Socket->Write32(challenge);
62
63 if (!Socket->SendData(Timeout))
64 return 0;
65
66 int32_t err = Socket->GetData(Timeout);
67
68 switch (err)
69 {
70 case -1:
71 case -3:
72 {
73 Socket->ClearBuffer();
74 --Retry;
75 continue;
76 };
77
78 case -2:
79 return 0;
80
81 default:
82 goto ok;
83 }
84 }
85
86 if (!Retry)
87 return 0;
88
89 ok:
90
91 Ping = Socket->GetPing();
92
93 if (!Parse())
94 return 0;
95
96 return 1;
97 }
98
99 /*
100 Read a packet received from a master server
101
102 If this already contains server addresses
103 it will be freed and reinitialized (horrible I know)
104 */
Parse()105 int32_t MasterServer::Parse()
106 {
107
108 // begin reading
109
110 uint32_t temp_response;
111
112 Socket->Read32(temp_response);
113
114 if (temp_response != response)
115 {
116 Socket->ClearBuffer();
117
118 return 0;
119 }
120
121 int16_t server_count;
122
123 Socket->Read16(server_count);
124
125 if (!server_count)
126 {
127 Socket->ClearBuffer();
128
129 return 0;
130 }
131
132 // Add on to any servers already in the list
133 if (server_count)
134 for (int16_t i = 0; i < server_count; i++)
135 {
136 addr_t address;
137 uint8_t ip1, ip2, ip3, ip4;
138
139 Socket->Read8(ip1);
140 Socket->Read8(ip2);
141 Socket->Read8(ip3);
142 Socket->Read8(ip4);
143
144 ostringstream stream;
145
146 stream << (int)ip1 << "." << (int)ip2 << "." << (int)ip3 << "." << (int)ip4;
147 address.ip = stream.str();
148
149 Socket->Read16(address.port);
150
151 address.custom = false;
152
153 size_t j = 0;
154
155 // Don't add the same address more than once.
156 for (j = 0; j < addresses.size(); ++j)
157 {
158 if (addresses[j].ip == address.ip &&
159 addresses[j].port == address.port)
160 {
161 break;
162 }
163 }
164
165 // didn't find it, so add it
166 if (j == addresses.size())
167 addresses.push_back(address);
168 }
169
170 if (Socket->BadRead())
171 {
172 Socket->ClearBuffer();
173
174 return 0;
175 }
176
177 Socket->ClearBuffer();
178
179 return 1;
180 }
181
182 // Server constructor
Server()183 Server::Server()
184 {
185 challenge = SERVER_CHALLENGE;
186
187 ResetData();
188 }
189
~Server()190 Server::~Server()
191 {
192 ResetData();
193 }
194
ResetData()195 void Server::ResetData()
196 {
197 m_ValidResponse = false;
198
199 Info.Cvars.clear();
200 Info.Wads.clear();
201 Info.Players.clear();
202 Info.Patches.clear();
203 Info.Teams.clear();
204
205 Info.Response = 0;
206 Info.VersionMajor = 0;
207 Info.VersionMinor = 0;
208 Info.VersionPatch = 0;
209 Info.VersionRevision = 0;
210 Info.VersionProtocol = 0;
211 Info.VersionRealProtocol = 0;
212 Info.PTime = 0;
213 Info.Name = "";
214 Info.MaxClients = 0;
215 Info.MaxPlayers = 0;
216 Info.ScoreLimit = 0;
217 Info.GameType = GT_Cooperative;
218 Info.PasswordHash = "";
219 Info.CurrentMap = "";
220 Info.TimeLeft = 0;
221
222 Ping = 0;
223 }
224
225 /*
226 Inclusion/Removal macros of certain fields, it is MANDATORY to remove these
227 with every new major/minor version
228 */
229
230 static uint8_t VersionMajor, VersionMinor, VersionPatch;
231 static uint32_t ProtocolVersion;
232
233 // Specifies when data was added to the protocol, the parameter is the
234 // introduced revision
235 // NOTE: this one is different from the servers version for a reason
236 #define QRYNEWINFO(INTRODUCED) \
237 if (ProtocolVersion >= INTRODUCED)
238
239 // Specifies when data was removed from the protocol, first parameter is the
240 // introduced revision and the last one is the removed revision
241 #define QRYRANGEINFO(INTRODUCED,REMOVED) \
242 if (ProtocolVersion >= INTRODUCED && ProtocolVersion < REMOVED)
243
244 // Read cvar information
ReadCvars()245 bool Server::ReadCvars()
246 {
247 uint8_t CvarCount;
248
249 Socket->Read8(CvarCount);
250
251 for (size_t i = 0; i < CvarCount; ++i)
252 {
253 Cvar_t Cvar;
254
255 Socket->ReadString(Cvar.Name);
256
257 QRYNEWINFO(3)
258 {
259 Socket->Read8(Cvar.Type);
260
261 switch (Cvar.Type)
262 {
263 case CVARTYPE_BOOL:
264 {
265 Cvar.b = true;
266 }
267 break;
268
269 case CVARTYPE_BYTE:
270 {
271 Socket->Read8(Cvar.i8);
272 }
273 break;
274
275 case CVARTYPE_WORD:
276 {
277 Socket->Read16(Cvar.i16);
278 }
279 break;
280
281 case CVARTYPE_INT:
282 {
283 Socket->Read32(Cvar.i32);
284 }
285 break;
286
287 case CVARTYPE_FLOAT:
288 case CVARTYPE_STRING:
289 {
290 Socket->ReadString(Cvar.Value);
291 }
292 break;
293
294 case CVARTYPE_NONE:
295 case CVARTYPE_MAX:
296 default:
297 break;
298 }
299 }
300 else
301 {
302 Cvar.Type = CVARTYPE_NONE;
303
304 Socket->ReadString(Cvar.Value);
305 }
306
307 // Filter out important information for us to use, it'd be nicer to have
308 // a launcher-side cvar implementation though
309 if (Cvar.Name == "sv_hostname")
310 {
311 Info.Name = Cvar.Value;
312
313 continue;
314 }
315 else if (Cvar.Name == "sv_maxplayers")
316 {
317 QRYNEWINFO(3)
318 Info.MaxPlayers = Cvar.ui8;
319 else
320 Info.MaxPlayers = (uint8_t)atoi(Cvar.Value.c_str());
321
322 continue;
323 }
324 else if (Cvar.Name == "sv_maxclients")
325 {
326 QRYNEWINFO(3)
327 Info.MaxClients = Cvar.ui8;
328 else
329 Info.MaxClients = (uint8_t)atoi(Cvar.Value.c_str());
330
331 continue;
332 }
333 else if (Cvar.Name == "sv_gametype")
334 {
335 QRYNEWINFO(3)
336 Info.GameType = (GameType_t)Cvar.ui8;
337 else
338 Info.GameType = (GameType_t)atoi(Cvar.Value.c_str());
339
340 continue;
341 }
342 else if (Cvar.Name == "sv_scorelimit")
343 {
344 QRYNEWINFO(3)
345 Info.ScoreLimit = Cvar.ui16;
346 else
347 Info.ScoreLimit = atoi(Cvar.Value.c_str());
348
349 continue;
350 }
351
352 Info.Cvars.push_back(Cvar);
353 }
354
355 return true;
356 }
357
358 // Read information built for us by the server
ReadInformation()359 void Server::ReadInformation()
360 {
361 Info.VersionMajor = VersionMajor;
362 Info.VersionMinor = VersionMinor;
363 Info.VersionPatch = VersionPatch;
364 Info.VersionProtocol = ProtocolVersion;
365
366 // bond - time
367 Socket->Read32(Info.PTime);
368
369 // The servers real protocol version
370 // bond - real protocol
371 Socket->Read32(Info.VersionRealProtocol);
372
373 Socket->Read32(Info.VersionRevision);
374
375 // Read cvar data
376 ReadCvars();
377
378 // TODO: Remove next release
379 QRYNEWINFO(4)
380 Socket->ReadHexString(Info.PasswordHash);
381 else
382 Socket->ReadString(Info.PasswordHash);
383
384 Socket->ReadString(Info.CurrentMap);
385 Socket->Read16(Info.TimeLeft);
386
387 // TODO: Remove next release
388 // Teams
389 QRYNEWINFO(5)
390 {
391 if (Info.GameType == GT_TeamDeathmatch ||
392 Info.GameType == GT_CaptureTheFlag)
393 {
394 uint8_t TeamCount;
395
396 Socket->Read8(TeamCount);
397
398 for (size_t i = 0; i < TeamCount; ++i)
399 {
400 Team_t Team;
401
402 Socket->ReadString(Team.Name);
403 Socket->Read32(Team.Colour);
404 Socket->Read16(Team.Score);
405
406 Info.Teams.push_back(Team);
407 }
408 }
409 }
410 else
411 {
412 uint8_t TeamCount;
413
414 Socket->Read8(TeamCount);
415
416 for (size_t i = 0; i < TeamCount; ++i)
417 {
418 Team_t Team;
419
420 Socket->ReadString(Team.Name);
421 Socket->Read32(Team.Colour);
422 Socket->Read16(Team.Score);
423
424 Info.Teams.push_back(Team);
425 }
426 }
427
428 // Dehacked/Bex files
429 uint8_t PatchCount;
430
431 Socket->Read8(PatchCount);
432
433 for (size_t i = 0; i < PatchCount; ++i)
434 {
435 string Patch;
436
437 Socket->ReadString(Patch);
438
439 Info.Patches.push_back(Patch);
440 }
441
442 // Wad files
443 uint8_t WadCount;
444
445 Socket->Read8(WadCount);
446
447 for (size_t i = 0; i < WadCount; ++i)
448 {
449 Wad_t Wad;
450
451 Socket->ReadString(Wad.Name);
452
453 // TODO: Remove next release
454 QRYNEWINFO(4)
455 Socket->ReadHexString(Wad.Hash);
456 else
457 Socket->ReadString(Wad.Hash);
458
459 Info.Wads.push_back(Wad);
460 }
461
462 // Player information
463 uint8_t PlayerCount;
464
465 Socket->Read8(PlayerCount);
466
467 for (size_t i = 0; i < PlayerCount; ++i)
468 {
469 Player_t Player;
470
471 Socket->ReadString(Player.Name);
472 Socket->Read32(Player.Colour);
473
474 QRYNEWINFO(5)
475 {
476 if (Info.GameType == GT_TeamDeathmatch ||
477 Info.GameType == GT_CaptureTheFlag)
478 {
479 Socket->Read8(Player.Team);
480 }
481 }
482 else
483 Socket->Read8(Player.Team);
484 Socket->Read16(Player.Ping);
485 Socket->Read16(Player.Time);
486 Socket->ReadBool(Player.Spectator);
487 Socket->Read16(Player.Frags);
488 Socket->Read16(Player.Kills);
489 Socket->Read16(Player.Deaths);
490
491 Info.Players.push_back(Player);
492 }
493 }
494
495 //
496 // Server::TranslateResponse()
497 //
498 // Figures out the response from the server, deciding whether to use this data
499 // or not
TranslateResponse(const uint16_t & TagId,const uint8_t & TagApplication,const uint8_t & TagQRId,const uint16_t & TagPacketType)500 int32_t Server::TranslateResponse(const uint16_t &TagId,
501 const uint8_t &TagApplication,
502 const uint8_t &TagQRId,
503 const uint16_t &TagPacketType)
504 {
505 // It isn't a response
506 if (TagQRId != 2)
507 {
508 //wxLogDebug(wxT("Query/Response Id is not valid"));
509
510 return 0;
511 }
512
513 switch (TagApplication)
514 {
515 // Enquirer
516 case 1:
517 {
518 //wxLogDebug(wxT("Application is Enquirer"));
519
520 return 0;
521 }
522 break;
523
524 // Client
525 case 2:
526 {
527 //wxLogDebug(wxT("Application is Client"));
528
529 return 0;
530 }
531 break;
532
533 // Server
534 case 3:
535 {
536 //wxLogDebug(wxT("Application is Server"));
537 }
538 break;
539
540 // Master Server
541 case 4:
542 {
543 //wxLogDebug(wxT("Application is Master Server"));
544
545 return 0;
546 }
547 break;
548
549 // Unknown
550 default:
551 {
552 //wxLogDebug(wxT("Application is Unknown"));
553
554 return 0;
555 }
556 break;
557 }
558
559 if (TagPacketType == 2)
560 {
561 // Launcher is an old version
562 NET_ReportError("Launcher is too old to parse the data from Server %s",
563 Socket->GetRemoteAddress().c_str());
564
565 return 0;
566 }
567
568 uint32_t SvVersion;
569 uint32_t SvProtocolVersion;
570
571 Socket->Read32(SvVersion);
572 Socket->Read32(SvProtocolVersion);
573
574 // Prevent possible divide by zero
575 if (!SvVersion)
576 {
577 return 0;
578 }
579
580 if ((VERSIONMAJOR(SvVersion) < VERSIONMAJOR(VERSION)) ||
581 (VERSIONMAJOR(SvVersion) <= VERSIONMAJOR(VERSION) && VERSIONMINOR(SvVersion) < VERSIONMINOR(VERSION)))
582 {
583 // Server is an older version
584 NET_ReportError("Server %s is version %d.%d.%d which is not supported\n",
585 Socket->GetRemoteAddress().c_str(),
586 VERSIONMAJOR(SvVersion),
587 VERSIONMINOR(SvVersion),
588 VERSIONPATCH(SvVersion));
589
590 return 0;
591 }
592
593 VersionMajor = VERSIONMAJOR(SvVersion);
594 VersionMinor = VERSIONMINOR(SvVersion);
595 VersionPatch = VERSIONPATCH(SvVersion);
596 ProtocolVersion = SvProtocolVersion;
597
598 ReadInformation();
599
600 if (Socket->BadRead())
601 {
602 // Bad packet data encountered
603 NET_ReportError("Data from Server %s was out of sequence, please report!\n",
604 Socket->GetRemoteAddress().c_str());
605
606 return 0;
607 }
608
609 // Success
610 return 1;
611 }
612
Parse()613 int32_t Server::Parse()
614 {
615 Socket->Read32(Info.Response);
616
617 // Decode the tag into its fields
618 // TODO: this may not be 100% correct
619 uint16_t TagId = ((Info.Response >> 20) & 0x0FFF);
620 uint8_t TagApplication = ((Info.Response >> 16) & 0x0F);
621 uint8_t TagQRId = ((Info.Response >> 12) & 0x0F);
622 uint16_t TagPacketType = (Info.Response & 0xFFFF0FFF);
623
624 if (TagId == TAG_ID)
625 {
626 int32_t Result = TranslateResponse(TagId,
627 TagApplication,
628 TagQRId,
629 TagPacketType);
630
631 Socket->ClearBuffer();
632
633 m_ValidResponse = Result ? true : false;
634
635 return Result;
636 }
637
638 m_ValidResponse = false;
639
640 Info.Response = 0;
641
642 Socket->ClearBuffer();
643
644 return 0;
645 }
646
Query(int32_t Timeout)647 int32_t Server::Query(int32_t Timeout)
648 {
649 int8_t Retry = m_RetryCount;
650
651 if (m_Address.empty() || !m_Port)
652 return 0;
653
654 Socket->SetRemoteAddress(m_Address, m_Port);
655
656 Socket->ClearBuffer();
657
658 ResetData();
659
660 // If we didn't get it the first time, try again
661 while (Retry)
662 {
663 Socket->Write32(challenge);
664 Socket->Write32(VERSION);
665 Socket->Write32(PROTOCOL_VERSION);
666 // bond - time
667 Socket->Write32(Info.PTime);
668
669 if (!Socket->SendData(Timeout))
670 return 0;
671
672 int32_t err = Socket->GetData(Timeout);
673
674 switch (err)
675 {
676 case -1:
677 case -3:
678 {
679 Socket->ResetBuffer();
680 Socket->ResetSize();
681 --Retry;
682 continue;
683 };
684
685 case -2:
686 return 0;
687
688 default:
689 goto ok;
690 }
691 }
692
693 if (!Retry)
694 return 0;
695
696 ok:
697
698 Ping = Socket->GetPing();
699
700 if (!Parse())
701 return 0;
702
703 return 1;
704 }
705
706 // Send network-wide broadcasts
QueryBC(const uint32_t & Timeout)707 void MasterServer::QueryBC(const uint32_t &Timeout)
708 {
709 BufferedSocket BCSocket;
710
711 BCSocket.ClearBuffer();
712
713 BCSocket.SetRemoteAddress("255.255.255.255", 10666);
714
715 // TODO: it might be better to create actual Server objects so we do not
716 // have to requery when we get past this stage
717 BCSocket.Write32(SERVER_VERSION_CHALLENGE);
718 BCSocket.Write32(VERSION);
719 BCSocket.Write32(PROTOCOL_VERSION);
720
721 BCSocket.Write32(0);
722
723 BCSocket.SetBroadcast(true);
724
725 BCSocket.SendData(Timeout);
726
727 while (BCSocket.GetData(Timeout) > 0)
728 {
729 addr_t address = { "", 0, false};
730 size_t j = 0;
731
732 address.custom = false;
733
734 BCSocket.GetRemoteAddress(address.ip, address.port);
735
736 // Don't add the same address more than once.
737 for (; j < addresses.size(); ++j)
738 {
739 if (addresses[j].ip == address.ip &&
740 addresses[j].port == address.port)
741 {
742 break;
743 }
744 }
745
746 // didn't find it, so add it
747 if (j == addresses.size())
748 addresses.push_back(address);
749 }
750 }
751
752 } // namespace
753