OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

tcp_content.cpp
Go to the documentation of this file.
1 /* $Id: tcp_content.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 */
9
14 #ifdef ENABLE_NETWORK
15
16 #include "../../stdafx.h"
17 #ifndef OPENTTD_MSU
18 #include "../../textfile_gui.h"
19 #include "../../newgrf_config.h"
20 #include "../../base_media_base.h"
21 #include "../../ai/ai.hpp"
22 #include "../../game/game.hpp"
23 #include "../../fios.h"
24 #endif /* OPENTTD_MSU */
25 #include "tcp_content.h"
26
27 #include "../../safeguards.h"
28
30 ContentInfo::ContentInfo()
31 {
32 memset(this, 0, sizeof(*this));
33 }
34
36 ContentInfo::~ContentInfo()
37 {
38 free(this->dependencies);
39 free(this->tags);
40 }
41
46 void ContentInfo::TransferFrom(ContentInfo *other)
47 {
48 if (other != this) {
49 free(this->dependencies);
50 free(this->tags);
51 memcpy(this, other, sizeof(ContentInfo));
52 other->dependencies = NULL;
53 other->tags = NULL;
54 }
55 }
56
61 size_t ContentInfo::Size() const
62 {
63 size_t len = 0;
64 for (uint i = 0; i < this->tag_count; i++) len += strlen(this->tags[i]) + 1;
65
66 /* The size is never larger than the content info size plus the size of the
67 * tags and dependencies */
68 return sizeof(*this) +
69 sizeof(this->dependency_count) +
70 sizeof(*this->dependencies) * this->dependency_count;
71 }
72
77 bool ContentInfo::IsSelected() const
78 {
79 switch (this->state) {
80 case ContentInfo::SELECTED:
81 case ContentInfo::AUTOSELECTED:
82 case ContentInfo::ALREADY_HERE:
83 return true;
84
85 default:
86 return false;
87 }
88 }
89
94 bool ContentInfo::IsValid() const
95 {
96 return this->state < ContentInfo::INVALID && this->type >= CONTENT_TYPE_BEGIN && this->type < CONTENT_TYPE_END;
97 }
98
99 #ifndef OPENTTD_MSU
100
105 const char *ContentInfo::GetTextfile(TextfileType type) const
106 {
107 if (this->state == INVALID) return NULL;
108 const char *tmp;
109 switch (this->type) {
110 default: NOT_REACHED();
111 case CONTENT_TYPE_AI:
112 tmp = AI::GetScannerInfo()->FindMainScript(this, true);
113 break;
114 case CONTENT_TYPE_AI_LIBRARY:
115 tmp = AI::GetScannerLibrary()->FindMainScript(this, true);
116 break;
117 case CONTENT_TYPE_GAME:
118 tmp = Game::GetScannerInfo()->FindMainScript(this, true);
119 break;
120 case CONTENT_TYPE_GAME_LIBRARY:
121 tmp = Game::GetScannerLibrary()->FindMainScript(this, true);
122 break;
123 case CONTENT_TYPE_NEWGRF: {
124 const GRFConfig *gc = FindGRFConfig(BSWAP32(this->unique_id), FGCM_EXACT, this->md5sum);
125 tmp = gc != NULL ? gc->filename : NULL;
126 break;
127 }
128 case CONTENT_TYPE_BASE_GRAPHICS:
129 tmp = TryGetBaseSetFile(this, true, BaseGraphics::GetAvailableSets());
130 break;
131 case CONTENT_TYPE_BASE_SOUNDS:
132 tmp = TryGetBaseSetFile(this, true, BaseSounds::GetAvailableSets());
133 break;
134 case CONTENT_TYPE_BASE_MUSIC:
135 tmp = TryGetBaseSetFile(this, true, BaseMusic::GetAvailableSets());
136 break;
137 case CONTENT_TYPE_SCENARIO:
138 case CONTENT_TYPE_HEIGHTMAP:
139 extern const char *FindScenario(const ContentInfo *ci, bool md5sum);
140 tmp = FindScenario(this, true);
141 break;
142 }
143 if (tmp == NULL) return NULL;
144 return ::GetTextfile(type, GetContentInfoSubDir(this->type), tmp);
145 }
146 #endif /* OPENTTD_MSU */
147
148 void NetworkContentSocketHandler::Close()
149 {
150 CloseConnection();
151 if (this->sock == INVALID_SOCKET) return;
152
153 closesocket(this->sock);
154 this->sock = INVALID_SOCKET;
155 }
156
163 bool NetworkContentSocketHandler::HandlePacket(Packet *p)
164 {
165 PacketContentType type = (PacketContentType)p->Recv_uint8();
166
167 switch (this->HasClientQuit() ? PACKET_CONTENT_END : type) {
168 case PACKET_CONTENT_CLIENT_INFO_LIST: return this->Receive_CLIENT_INFO_LIST(p);
169 case PACKET_CONTENT_CLIENT_INFO_ID: return this->Receive_CLIENT_INFO_ID(p);
170 case PACKET_CONTENT_CLIENT_INFO_EXTID: return this->Receive_CLIENT_INFO_EXTID(p);
171 case PACKET_CONTENT_CLIENT_INFO_EXTID_MD5: return this->Receive_CLIENT_INFO_EXTID_MD5(p);
172 case PACKET_CONTENT_SERVER_INFO: return this->Receive_SERVER_INFO(p);
173 case PACKET_CONTENT_CLIENT_CONTENT: return this->Receive_CLIENT_CONTENT(p);
174 case PACKET_CONTENT_SERVER_CONTENT: return this->Receive_SERVER_CONTENT(p);
175
176 default:
177 if (this->HasClientQuit()) {
178 DEBUG(net, 0, "[tcp/content] received invalid packet type %d from %s", type, this->client_addr.GetAddressAsString());
179 } else {
180 DEBUG(net, 0, "[tcp/content] received illegal packet from %s", this->client_addr.GetAddressAsString());
181 }
182 return false;
183 }
184 }
185
190 bool NetworkContentSocketHandler::ReceivePackets()
191 {
192 /*
193 * We read only a few of the packets. This as receiving packets can be expensive
194 * due to the re-resolving of the parent/child relations and checking the toggle
195 * state of all bits. We cannot do this all in one go, as we want to show the
196 * user what we already received. Otherwise, it can take very long before any
197 * progress is shown to the end user that something has been received.
198 * It is also the case that we request extra content from the content server in
199 * case there is an unknown (in the content list) piece of content. These will
200 * come in after the main lists have been requested. As a result, we won't be
201 * getting everything reliably in one batch. Thus, we need to make subsequent
202 * updates in that case as well.
203 *
204 * As a result, we simple handle an arbitrary number of packets in one cycle,
205 * and let the rest be handled in subsequent cycles. These are ran, almost,
206 * immediately after this cycle so in speed it does not matter much, except
207 * that the user inferface will appear better responding.
208 *
209 * What arbitrary number to choose is the ultimate question though.
210 */
211 Packet *p;
212 static const int MAX_PACKETS_TO_RECEIVE = 42;
213 int i = MAX_PACKETS_TO_RECEIVE;
214 while (--i != 0 && (p = this->ReceivePacket()) != NULL) {
215 bool cont = this->HandlePacket(p);
216 delete p;
217 if (!cont) return true;
218 }
219
220 return i != MAX_PACKETS_TO_RECEIVE - 1;
221 }
222
223
229 bool NetworkContentSocketHandler::ReceiveInvalidPacket(PacketContentType type)
230 {
231 DEBUG(net, 0, "[tcp/content] received illegal packet type %d from %s", type, this->client_addr.GetAddressAsString());
232 return false;
233 }
234
235 bool NetworkContentSocketHandler::Receive_CLIENT_INFO_LIST(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_LIST); }
236 bool NetworkContentSocketHandler::Receive_CLIENT_INFO_ID(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_ID); }
237 bool NetworkContentSocketHandler::Receive_CLIENT_INFO_EXTID(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_EXTID); }
238 bool NetworkContentSocketHandler::Receive_CLIENT_INFO_EXTID_MD5(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_EXTID_MD5); }
239 bool NetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_INFO); }
240 bool NetworkContentSocketHandler::Receive_CLIENT_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_CONTENT); }
241 bool NetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_CONTENT); }
242
243 #ifndef OPENTTD_MSU
244
249 Subdirectory GetContentInfoSubDir(ContentType type)
250 {
251 switch (type) {
252 default: return NO_DIRECTORY;
253 case CONTENT_TYPE_AI: return AI_DIR;
254 case CONTENT_TYPE_AI_LIBRARY: return AI_LIBRARY_DIR;
255 case CONTENT_TYPE_GAME: return GAME_DIR;
256 case CONTENT_TYPE_GAME_LIBRARY: return GAME_LIBRARY_DIR;
257 case CONTENT_TYPE_NEWGRF: return NEWGRF_DIR;
258
259 case CONTENT_TYPE_BASE_GRAPHICS:
260 case CONTENT_TYPE_BASE_SOUNDS:
261 case CONTENT_TYPE_BASE_MUSIC:
262 return BASESET_DIR;
263
264 case CONTENT_TYPE_SCENARIO: return SCENARIO_DIR;
265 case CONTENT_TYPE_HEIGHTMAP: return HEIGHTMAP_DIR;
266 }
267 }
268 #endif /* OPENTTD_MSU */
269
270 #endif /* ENABLE_NETWORK */