OpenTTD
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 
31 {
32  memset(this, 0, sizeof(*this));
33 }
34 
37 {
38  free(this->dependencies);
39  free(this->tags);
40 }
41 
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 
78 {
79  switch (this->state) {
83  return true;
84 
85  default:
86  return false;
87  }
88 }
89 
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;
115  tmp = AI::GetScannerLibrary()->FindMainScript(this, true);
116  break;
117  case CONTENT_TYPE_GAME:
118  tmp = Game::GetScannerInfo()->FindMainScript(this, true);
119  break;
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  }
130  break;
132  tmp = TryGetBaseSetFile(this, true, BaseSounds::GetAvailableSets());
133  break;
135  tmp = TryGetBaseSetFile(this, true, BaseMusic::GetAvailableSets());
136  break;
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 
149 {
150  CloseConnection();
151  if (this->sock == INVALID_SOCKET) return;
152 
153  closesocket(this->sock);
154  this->sock = INVALID_SOCKET;
155 }
156 
164 {
166 
167  switch (this->HasClientQuit() ? PACKET_CONTENT_END : type) {
172  case PACKET_CONTENT_SERVER_INFO: return this->Receive_SERVER_INFO(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 
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 
230 {
231  DEBUG(net, 0, "[tcp/content] received illegal packet type %d from %s", type, this->client_addr.GetAddressAsString());
232  return false;
233 }
234 
242 
243 #ifndef OPENTTD_MSU
244 
250 {
251  switch (type) {
252  default: return NO_DIRECTORY;
253  case CONTENT_TYPE_AI: return AI_DIR;
255  case CONTENT_TYPE_GAME: return GAME_DIR;
257  case CONTENT_TYPE_NEWGRF: return NEWGRF_DIR;
258 
262  return BASESET_DIR;
263 
264  case CONTENT_TYPE_SCENARIO: return SCENARIO_DIR;
266  }
267 }
268 #endif /* OPENTTD_MSU */
269 
270 #endif /* ENABLE_NETWORK */