1 ////////////////////////////////////////////////////////////////////////////////
2 //    Scorched3D (c) 2000-2011
3 //
4 //    This file is part of Scorched3D.
5 //
6 //    Scorched3D is free software; you can redistribute it and/or modify
7 //    it under the terms of the GNU General Public License as published by
8 //    the Free Software Foundation; either version 2 of the License, or
9 //    (at your option) any later version.
10 //
11 //    Scorched3D is distributed in the hope that it will be useful,
12 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //    GNU General Public License for more details.
15 //
16 //    You should have received a copy of the GNU General Public License along
17 //    with this program; if not, write to the Free Software Foundation, Inc.,
18 //    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20 
21 #include <server/ServerMessageHandler.h>
22 #include <server/ScorchedServer.h>
23 #include <server/ServerCommon.h>
24 #include <server/ServerBanned.h>
25 #include <server/ServerChannelManager.h>
26 #include <server/ServerDestinations.h>
27 #include <server/ServerSimulator.h>
28 #include <server/ServerState.h>
29 #include <tank/TankDeadContainer.h>
30 #include <target/TargetContainer.h>
31 #include <tank/TankState.h>
32 #include <tankai/TankAINone.h>
33 #include <simactions/TankRemoveSimAction.h>
34 #include <coms/ComsMessageSender.h>
35 #include <net/NetInterface.h>
36 #include <common/Logger.h>
37 #include <common/OptionsScorched.h>
38 #include <common/StatsLogger.h>
39 
ServerMessageHandler()40 ServerMessageHandler::ServerMessageHandler()
41 {
42 }
43 
~ServerMessageHandler()44 ServerMessageHandler::~ServerMessageHandler()
45 {
46 }
47 
messageRecv(unsigned int destinationId)48 void ServerMessageHandler::messageRecv(unsigned int destinationId)
49 {
50 }
51 
messageSent(unsigned int destinationId)52 void ServerMessageHandler::messageSent(unsigned int destinationId)
53 {
54 }
55 
clientConnected(NetMessage & message)56 void ServerMessageHandler::clientConnected(NetMessage &message)
57 {
58 	// Check if this destination has been banned
59 	if (message.getIpAddress() != 0 &&
60 		ScorchedServer::instance()->getBannedPlayers().getBanned(message.getIpAddress()) ==
61 		ServerBanned::Banned)
62 	{
63 		Logger::log(S3D::formatStringBuffer("Banned client connected dest=\"%i\" ip=\"%s\"",
64 			message.getDestinationId(),
65 			NetInterface::getIpName(message.getIpAddress())));
66 		ScorchedServer::instance()->getNetInterface().
67 			disconnectClient(message.getDestinationId());
68 		return;
69 	}
70 
71 	// Check if a player from this destination has connected already
72 	std::map<unsigned int, ServerDestination *> &destinations =
73 		ScorchedServer::instance()->getServerDestinations().getServerDestinations();
74 	std::map<unsigned int, ServerDestination *>::iterator destItor;
75 	for (destItor = destinations.begin();
76 		destItor != destinations.end();
77 		++destItor)
78 	{
79 		unsigned int serverDestinationId = destItor->first;
80 		ServerDestination *serverDestination = destItor->second;
81 		if (serverDestinationId == message.getDestinationId())
82 		{
83 			Logger::log(S3D::formatStringBuffer("Duplicate connection from destination \"%i\"",
84 				message.getDestinationId()));
85 			ScorchedServer::instance()->getNetInterface().
86 				disconnectClient(message.getDestinationId());
87 			return;
88 		}
89 
90 		if (!ScorchedServer::instance()->getOptionsGame().getAllowSameIP() &&
91 			message.getIpAddress() != 0)
92 		{
93 			if (message.getIpAddress() == serverDestination->getIpAddress())
94 			{
95 				Logger::log(S3D::formatStringBuffer("Duplicate ip connection from ip address \"%s\"",
96 					NetInterface::getIpName(message.getIpAddress())));
97 				ScorchedServer::instance()->getNetInterface().
98 					disconnectClient(message.getDestinationId());
99 				return;
100 			}
101 		}
102 	}
103 
104 	// Add to list of destinations
105 	ScorchedServer::instance()->getServerDestinations().addDestination(
106 		message.getDestinationId(), message.getIpAddress());
107 
108 	Logger::log(S3D::formatStringBuffer("Client connected dest=\"%i\" ip=\"%s\"",
109 		message.getDestinationId(),
110 		NetInterface::getIpName(message.getIpAddress())));
111 }
112 
clientDisconnected(NetMessage & message)113 void ServerMessageHandler::clientDisconnected(NetMessage &message)
114 {
115 	const char *reason = "Unknown";
116 	if (message.getFlags() == NetMessage::UserDisconnect) reason = "User";
117 	else if (message.getFlags() == NetMessage::KickDisconnect) reason = "Kicked";
118 	else if (message.getFlags() == NetMessage::TimeoutDisconnect) reason = "Timeout";
119 
120 	Logger::log(S3D::formatStringBuffer("Client disconnected dest=\"%i\" ip=\"%s\" reason=\"%s\"",
121 		message.getDestinationId(),
122 		NetInterface::getIpName(message.getIpAddress()),
123 		reason));
124 
125 	// Build up a list of players at this destination
126 	std::list<unsigned int> removePlayers;
127 	unsigned int destinationId = message.getDestinationId();
128 	std::map<unsigned int, Tank *>::iterator itor;
129 	std::map<unsigned int, Tank *> &tanks =
130 		ScorchedServer::instance()->getTargetContainer().getTanks();
131 	for (itor = tanks.begin();
132 		itor != tanks.end();
133 		++itor)
134 	{
135 		Tank *tank = (*itor).second;
136 		if (tank->getDestinationId() == destinationId)
137 		{
138 			removePlayers.push_back(tank->getPlayerId());
139 		}
140 	}
141 
142 	// Remove all players for this destination
143 	std::list<unsigned int>::iterator remItor;
144 	for (remItor = removePlayers.begin();
145 		 remItor != removePlayers.end();
146 		 ++remItor)
147 	{
148 		unsigned int playerId = *remItor;
149 		destroyPlayer(playerId, reason);
150 	}
151 
152 	// Inform the channel manager
153 	ScorchedServer::instance()->getServerChannelManager().destinationDisconnected(message.getDestinationId());
154 
155 	// Remove from list of destinations
156 	ScorchedServer::instance()->getServerDestinations().removeDestination(
157 		message.getDestinationId());
158 }
159 
destroyPlayer(unsigned int tankId,const char * reason)160 void ServerMessageHandler::destroyPlayer(unsigned int tankId, const char *reason)
161 {
162 	// Try to remove this player
163 	Tank *tank = ScorchedServer::instance()->getTargetContainer().getTankById(tankId);
164 	if (!tank)
165 	{
166 		Logger::log(S3D::formatStringBuffer("Unknown player disconnected id=\"%i\" (%s)",
167 			tankId, reason));
168 		return;
169 	}
170 
171 	// Log disconnect
172 	Logger::log(
173 		S3D::formatStringBuffer("Player disconnected dest=\"%i\" ip=\"%s\" id=\"%i\" name=\"%s\" reason=\"%s\"",
174 		tank->getDestinationId(),
175 		NetInterface::getIpName(tank->getIpAddress()),
176 		tankId,
177 		tank->getCStrName().c_str(),
178 		reason));
179 	ScorchedServer::instance()->getServerChannelManager().sendText(
180 		ChannelText("info",
181 			"PLAYER_DISCONNECTED",
182 			"Player disconnected [p:{0}] ({1})",
183 			tank->getTargetName(), reason),
184 		true);
185 
186 	// Add tank to tank dead container to remember its stats
187 	if (ScorchedServer::instance()->getOptionsGame().getResidualPlayers())
188 	{
189 		if (tank->getState().getTankPlaying() &&
190 			tank->getDestinationId() != 0)
191 		{
192 			if (tank->getUniqueId()[0])
193 			{
194 				ScorchedServer::instance()->getTankDeadContainer().addDeadTank(tank, tank->getUniqueId());
195 			}
196 			else if (tank->getSUI()[0])
197 			{
198 				ScorchedServer::instance()->getTankDeadContainer().addDeadTank(tank, tank->getSUI());
199 			}
200 		}
201 	}
202 
203 	// The time to actualy remove the tank after
204 	fixed removalTime = 0;
205 
206 	// Check if we can remove player
207 	if (tank->getState().getState() == TankState::sNormal &&
208 		ScorchedServer::instance()->getServerState().getState() ==
209 		ServerState::ServerPlayingState &&
210 		tank->getDestinationId() != 0)
211 	{
212 		// Actualy remove the tank after a few seconds have passed
213 		removalTime = ScorchedServer::instance()->getOptionsGame().getRemoveTime();
214 	}
215 
216 	// Log the removal
217 	StatsLogger::instance()->tankDisconnected(tank);
218 
219 	// Actualy remove the tank from the client and server
220 	TankRemoveSimAction *removeSimAction =
221 		new TankRemoveSimAction(tankId, removalTime);
222 	ScorchedServer::instance()->getServerSimulator().
223 		addSimulatorAction(removeSimAction);
224 }
225 
clientError(NetMessage & message,const std::string & errorString)226 void ServerMessageHandler::clientError(NetMessage &message,
227 	const std::string &errorString)
228 {
229 	Logger::log(S3D::formatStringBuffer("Client \"%i\", ***Server Error*** \"%s\"",
230 		message.getDestinationId(),
231 		errorString.c_str()));
232 	ServerCommon::kickDestination(message.getDestinationId(),
233 		"Coms message error");
234 }
235