1 //       _________ __                 __
2 //      /   _____//  |_____________ _/  |______     ____  __ __  ______
3 //      \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
4 //      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ |
5 //     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
6 //             \/                  \/          \//_____/            \/
7 //  ______________________                           ______________________
8 //                        T H E   W A R   B E G I N S
9 //         Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name master.cpp - The master server. */
12 //
13 //      (c) Copyright 2003-2007 by Tom Zickel and Jimmy Salmon
14 //
15 //      This program is free software; you can redistribute it and/or modify
16 //      it under the terms of the GNU General Public License as published by
17 //      the Free Software Foundation; only version 2 of the License.
18 //
19 //      This program is distributed in the hope that it will be useful,
20 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //      GNU General Public License for more details.
23 //
24 //      You should have received a copy of the GNU General Public License
25 //      along with this program; if not, write to the Free Software
26 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 //      02111-1307, USA.
28 //
29 
30 //@{
31 
32 /*----------------------------------------------------------------------------
33 --  Includes
34 ----------------------------------------------------------------------------*/
35 
36 #include <errno.h>
37 #include <stdarg.h>
38 #include <ctype.h>
39 #include <limits.h>
40 
41 #include "stratagus.h"
42 
43 #include "master.h"
44 
45 #include "game.h"
46 #include "network/netsockets.h"
47 #include "network.h"
48 #include "net_lowlevel.h"
49 #include "parameters.h"
50 #include "script.h"
51 #include "version.h"
52 
53 
54 /*----------------------------------------------------------------------------
55 --  Variables
56 ----------------------------------------------------------------------------*/
57 
58 CMetaClient MetaClient;
59 
60 /*----------------------------------------------------------------------------
61 --  Functions
62 ----------------------------------------------------------------------------*/
63 
64 /**
65 **  Set the metaserver to use for internet play.
66 **
67 **  @param host  Host to connect
68 **  @param port  Port to use to connect
69 */
SetMetaServer(const std::string host,const int port)70 void CMetaClient::SetMetaServer(const std::string host, const int port)
71 {
72 	metaHost = host;
73 	metaPort = port;
74 }
75 
~CMetaClient()76 CMetaClient::~CMetaClient()
77 {
78 	for (std::list<CClientLog *>::iterator it = events.begin(); it != events.end(); ++it) {
79 		CClientLog *log = *it;
80 		delete log;
81 	}
82 	events.clear();
83 	this->Close();
84 }
85 
86 /**
87 **  Initialize the TCP connection to the Meta Server and send test ping to it.
88 **
89 **  @return  -1 fail, 0 success.
90 */
Init()91 int CMetaClient::Init()
92 {
93 	if (metaPort == -1) {
94 		return -1;
95 	}
96 
97 	// Server socket
98 	CHost metaServerHost(metaHost.c_str(), metaPort);
99 	// Client socket
100 	CHost metaClientHost(CNetworkParameter::Instance.localHost.c_str(), CNetworkParameter::Instance.localPort);
101 	metaSocket.Open(metaClientHost);
102 	if (metaSocket.IsValid() == false) {
103 		fprintf(stderr, "METACLIENT: No free port %d available, aborting\n", metaServerHost.getPort());
104 		return -1;
105 	}
106 	if (metaSocket.Connect(metaServerHost) == false) {
107 		fprintf(stderr, "METACLIENT: Unable to connect to host %s\n", metaServerHost.toString().c_str());
108 		MetaClient.Close();
109 		return -1;
110 	}
111 
112 	if (this->Send("PING") == -1) { // not sent
113 		MetaClient.Close();
114 		return -1;
115 	}
116 	if (this->Recv() == -1) { // not received
117 		MetaClient.Close();
118 		return -1;
119 	}
120 	CClientLog &log = *GetLastMessage();
121 	if (log.entry.find("PING_OK") != std::string::npos) {
122 		// Everything is OK
123 		return 0;
124 	} else {
125 		fprintf(stderr, "METACLIENT: inappropriate message received from %s\n", metaServerHost.toString().c_str());
126 		MetaClient.Close();
127 		return -1;
128 	}
129 }
130 
131 /**
132 **  Close Connection to Master Server
133 **
134 **  @return  nothing
135 */
Close()136 void CMetaClient::Close()
137 {
138 	if (metaSocket.IsValid()) {
139 		metaSocket.Close();
140 	}
141 }
142 
143 
144 /**
145 **  Send a command to the meta server
146 **
147 **  @param cmd   command to send
148 **
149 **  @returns     -1 if failed, otherwise length of command
150 */
Send(const std::string cmd)151 int CMetaClient::Send(const std::string cmd)
152 {
153 	int ret = -1;
154 	std::string mes(cmd);
155 	mes.append("\n");
156 	ret = metaSocket.Send(mes.c_str(), mes.size());
157 	return ret;
158 }
159 
160 /**
161 **  Receive reply from Meta Server
162 **
163 **  @return error or number of bytes
164 */
Recv()165 int CMetaClient::Recv()
166 {
167 	if (metaSocket.HasDataToRead(5000) == -1) {
168 		return -1;
169 	}
170 
171 	char buf[1024];
172 	memset(&buf, 0, sizeof(buf));
173 	int n = metaSocket.Recv(&buf, sizeof(buf));
174 	if (n == -1) {
175 		return n;
176 	}
177 	// We know we now have the whole command.
178 	// Convert to standard notation
179 	std::string cmd(buf, strlen(buf));
180 	cmd += '\n';
181 	cmd += '\0';
182 	CClientLog *log = new CClientLog;
183 	log->entry = cmd;
184 	events.push_back(log);
185 	lastRecvState = n;
186 	return n;
187 }
188 
189 //@}
190