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