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 <coms/ComsMessageHandler.h>
22 #include <common/Defines.h>
23 #include <common/Logger.h>
24 
~ComsMessageConnectionHandlerI()25 ComsMessageConnectionHandlerI::~ComsMessageConnectionHandlerI()
26 {
27 }
28 
~ComsMessageHandlerI()29 ComsMessageHandlerI::~ComsMessageHandlerI()
30 {
31 }
32 
ComsMessageHandler(const char * instanceName)33 ComsMessageHandler::ComsMessageHandler(const char *instanceName) :
34 	instanceName_(instanceName),
35 	connectionHandler_(0), comsMessageLogging_(false)
36 {
37 }
38 
~ComsMessageHandler()39 ComsMessageHandler::~ComsMessageHandler()
40 {
41 }
42 
setConnectionHandler(ComsMessageConnectionHandlerI * handler)43 void ComsMessageHandler::setConnectionHandler(
44 		ComsMessageConnectionHandlerI *handler)
45 {
46 	connectionHandler_ = handler;
47 }
48 
addHandler(ComsMessageType & comsMessageType,ComsMessageHandlerI * handler)49 void ComsMessageHandler::addHandler(ComsMessageType &comsMessageType,
50 		ComsMessageHandlerI *handler)
51 {
52 	unsigned int id = comsMessageType.getId();
53 	if (recvHandlers_.size() < id + 1) recvHandlers_.resize(id + 1);
54 	recvHandlers_[id] = handler;
55 }
56 
addSentHandler(ComsMessageType & comsMessageType,ComsMessageHandlerI * handler)57 void ComsMessageHandler::addSentHandler(ComsMessageType &comsMessageType,
58 		ComsMessageHandlerI *handler)
59 {
60 	unsigned int id = comsMessageType.getId();
61 	if (sentHandlers_.size() < id + 1) sentHandlers_.resize(id + 1);
62 	sentHandlers_[id] = handler;
63 }
64 
processMessage(NetMessage & message)65 void ComsMessageHandler::processMessage(NetMessage &message)
66 {
67 	switch(message.getMessageType())
68 	{
69 		case NetMessage::BufferMessage:
70 			if (connectionHandler_)
71 				connectionHandler_->messageRecv(message.getDestinationId());
72 			processReceiveMessage(message);
73 			break;
74 		case NetMessage::SentMessage:
75 			if (connectionHandler_)
76 				connectionHandler_->messageSent(message.getDestinationId());
77 			processSentMessage(message);
78 			break;
79 		case NetMessage::DisconnectMessage:
80 			if (comsMessageLogging_)
81 			{
82 				Logger::log(S3D::formatStringBuffer("ComsMessage::Disconnected(%i, %i)",
83 					message.getDestinationId(), message.getFlags()));
84 			}
85 
86 			if (connectionHandler_)
87 				connectionHandler_->clientDisconnected(message);
88 			break;
89 		case NetMessage::ConnectMessage:
90 			if (comsMessageLogging_)
91 			{
92 				Logger::log(S3D::formatStringBuffer("ComsMessage::Connected(%i)",
93 					message.getDestinationId()));
94 			}
95 
96 			if (connectionHandler_)
97 				connectionHandler_->clientConnected(message);
98 			break;
99 		default:
100 			if (connectionHandler_)
101 				connectionHandler_->clientError(message,
102 					"Failed to recognise message type");
103 			break;
104 	}
105 }
106 
processReceiveMessage(NetMessage & message)107 void ComsMessageHandler::processReceiveMessage(NetMessage &message)
108 {
109 	processMessage(message, recvHandlers_, "RECV");
110 }
111 
processSentMessage(NetMessage & message)112 void ComsMessageHandler::processSentMessage(NetMessage &message)
113 {
114 	processMessage(message, sentHandlers_, "SEND");
115 }
116 
processMessage(NetMessage & message,std::vector<ComsMessageHandlerI * > & handlers,const char * sendRecv)117 void ComsMessageHandler::processMessage(NetMessage &message,
118 	std::vector<ComsMessageHandlerI *> &handlers,
119 	const char *sendRecv)
120 {
121 	if (handlers.empty()) return;
122 
123 	// Get how big the buffer is
124 	unsigned int bufferUsed = message.getBuffer().getBufferUsed();
125 	if (bufferUsed < 1)
126 	{
127 		if (connectionHandler_)
128 			connectionHandler_->clientError(message,
129 				S3D::formatStringBuffer("Failed to get %s message compression state", sendRecv));
130 	}
131 
132 	// Check if the buffer is sent compressed
133 	bool compressed = (message.getBuffer().getBuffer()[bufferUsed - 1] == '1');
134 	message.getBuffer().setBufferUsed(bufferUsed - 1);
135 	if (compressed)
136 	{
137 		if (!message.getBuffer().uncompressBuffer())
138 		{
139 			if (connectionHandler_)
140 				connectionHandler_->clientError(message,
141 					S3D::formatStringBuffer("Failed to uncompress %s message", sendRecv));
142 		}
143 	}
144 	NetBufferReader reader(message.getBuffer());
145 
146 	unsigned char messageTypeId;
147 	if (!reader.getFromBuffer(messageTypeId))
148 	{
149 		if (connectionHandler_)
150 			connectionHandler_->clientError(message,
151 				S3D::formatStringBuffer("Failed to decode %s message type", sendRecv));
152 		return;
153 	}
154 	ComsMessageType *comsMessageType = ComsMessageType::getTypeForId(messageTypeId);
155 	if (!comsMessageType)
156 	{
157 		if (connectionHandler_)
158 			connectionHandler_->clientError(message,
159 				S3D::formatStringBuffer("Failed to find %s message type %u",
160 				sendRecv, messageTypeId));
161 		return;
162 	}
163 	const char *messageTypeStr = comsMessageType->getName().c_str();
164 
165 	if (comsMessageLogging_)
166 	{
167 		Logger::log(S3D::formatStringBuffer("%s::process%s(%s, %i, %u%s)",
168 			instanceName_.c_str(),
169 			sendRecv,
170 			messageTypeStr, message.getDestinationId(),
171 			bufferUsed,
172 			compressed?", compressed":""));
173 	}
174 	if (messageTypeId >= handlers.size())
175 	{
176 		if (connectionHandler_)
177 			connectionHandler_->clientError(message,
178 				S3D::formatStringBuffer("Failed to find %s message type handler \"%s\"",
179 					sendRecv, messageTypeStr));
180 		return;
181 	}
182 	ComsMessageHandlerI *handler = handlers[messageTypeId];
183 	if (!handler)
184 	{
185 		if (connectionHandler_)
186 			connectionHandler_->clientError(message,
187 				S3D::formatStringBuffer("Failed to find %s message type handler \"%s\"",
188 					sendRecv, messageTypeStr));
189 		return;
190 	}
191 	if (!handler->processMessage(
192 		message, messageTypeStr, reader))
193 	{
194 		if (connectionHandler_)
195 			connectionHandler_->clientError(message,
196 				S3D::formatStringBuffer("Failed to handle %s message type handler \"%s\"",
197 					sendRecv, messageTypeStr));
198 		return;
199 	}
200 
201 	if (comsMessageLogging_)
202 	{
203 		Logger::log(S3D::formatStringBuffer("%s::processFinished%s(%s, %i)",
204 			instanceName_.c_str(),
205 			sendRecv,
206 			messageTypeStr, message.getDestinationId()));
207 	}
208 }
209