# tcp_content.cpp

Go to the documentation of this file.

    00001 /* $Id: tcp_content.cpp 25597 2013-07-13 09:26:11Z rubidium $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00014 #ifdef ENABLE_NETWORK
    00015
    00016 #include "../../stdafx.h"
    00017 #ifndef OPENTTD_MSU
    00018 #include "../../textfile_gui.h"
    00019 #include "../../newgrf_config.h"
    00020 #include "../../base_media_base.h"
    00021 #include "../../ai/ai.hpp"
    00022 #include "../../game/game.hpp"
    00023 #include "../../fios.h"
    00024 #endif /* OPENTTD_MSU */
    00025 #include "tcp_content.h"
    00026
    00028 ContentInfo::ContentInfo()
    00029 {
    00030   memset(this, 0, sizeof(*this));
    00031 }
    00032
    00034 ContentInfo::~ContentInfo()
    00035 {
    00036   free(this->dependencies);
    00037   free(this->tags);
    00038 }
    00039
    00044 void ContentInfo::TransferFrom(ContentInfo *other)
    00045 {
    00046   if (other != this) {
    00047     free(this->dependencies);
    00048     free(this->tags);
    00049     memcpy(this, other, sizeof(ContentInfo));
    00050     other->dependencies = NULL;
    00051     other->tags = NULL;
    00052   }
    00053 }
    00054
    00059 size_t ContentInfo::Size() const
    00060 {
    00061   size_t len = 0;
    00062   for (uint i = 0; i < this->tag_count; i++) len += strlen(this->tags[i]) + 1;
    00063
    00064   /* The size is never larger than the content info size plus the size of the
    00065    * tags and dependencies */
    00066   return sizeof(*this) +
    00067       sizeof(this->dependency_count) +
    00068       sizeof(*this->dependencies) * this->dependency_count;
    00069 }
    00070
    00075 bool ContentInfo::IsSelected() const
    00076 {
    00077   switch (this->state) {
    00078     case ContentInfo::SELECTED:
    00079     case ContentInfo::AUTOSELECTED:
    00080     case ContentInfo::ALREADY_HERE:
    00081       return true;
    00082
    00083     default:
    00084       return false;
    00085   }
    00086 }
    00087
    00092 bool ContentInfo::IsValid() const
    00093 {
    00094   return this->state < ContentInfo::INVALID && this->type >= CONTENT_TYPE_BEGIN && this->type < CONTENT_TYPE_END;
    00095 }
    00096
    00097 #ifndef OPENTTD_MSU
    00098
    00103 const char *ContentInfo::GetTextfile(TextfileType type) const
    00104 {
    00105   if (this->state == INVALID) return NULL;
    00106   const char *tmp;
    00107   switch (this->type) {
    00108     default: NOT_REACHED();
    00109     case CONTENT_TYPE_AI:
    00110       tmp = AI::GetScannerInfo()->FindMainScript(this, true);
    00111       break;
    00112     case CONTENT_TYPE_AI_LIBRARY:
    00113       tmp = AI::GetScannerLibrary()->FindMainScript(this, true);
    00114       break;
    00115     case CONTENT_TYPE_GAME:
    00116       tmp = Game::GetScannerInfo()->FindMainScript(this, true);
    00117       break;
    00118     case CONTENT_TYPE_GAME_LIBRARY:
    00119       tmp = Game::GetScannerLibrary()->FindMainScript(this, true);
    00120       break;
    00121     case CONTENT_TYPE_NEWGRF: {
    00122       const GRFConfig *gc = FindGRFConfig(BSWAP32(this->unique_id), FGCM_EXACT, this->md5sum);
    00123       tmp = gc != NULL ? gc->filename : NULL;
    00124       break;
    00125     }
    00126     case CONTENT_TYPE_BASE_GRAPHICS:
    00127       tmp = TryGetBaseSetFile(this, true, BaseGraphics::GetAvailableSets());
    00128       break;
    00129     case CONTENT_TYPE_BASE_SOUNDS:
    00130       tmp = TryGetBaseSetFile(this, true, BaseSounds::GetAvailableSets());
    00131       break;
    00132     case CONTENT_TYPE_BASE_MUSIC:
    00133       tmp = TryGetBaseSetFile(this, true, BaseMusic::GetAvailableSets());
    00134       break;
    00135     case CONTENT_TYPE_SCENARIO:
    00136     case CONTENT_TYPE_HEIGHTMAP:
    00137       extern const char *FindScenario(const ContentInfo *ci, bool md5sum);
    00138       tmp = FindScenario(this, true);
    00139       break;
    00140   }
    00141   if (tmp == NULL) return NULL;
    00142   return ::GetTextfile(type, GetContentInfoSubDir(this->type), tmp);
    00143 }
    00144 #endif /* OPENTTD_MSU */
    00145
    00146 void NetworkContentSocketHandler::Close()
    00147 {
    00148   CloseConnection();
    00149   if (this->sock == INVALID_SOCKET) return;
    00150
    00151   closesocket(this->sock);
    00152   this->sock = INVALID_SOCKET;
    00153 }
    00154
    00161 bool NetworkContentSocketHandler::HandlePacket(Packet *p)
    00162 {
    00163   PacketContentType type = (PacketContentType)p->Recv_uint8();
    00164
    00165   switch (this->HasClientQuit() ? PACKET_CONTENT_END : type) {
    00166     case PACKET_CONTENT_CLIENT_INFO_LIST:      return this->Receive_CLIENT_INFO_LIST(p);
    00167     case PACKET_CONTENT_CLIENT_INFO_ID:        return this->Receive_CLIENT_INFO_ID(p);
    00168     case PACKET_CONTENT_CLIENT_INFO_EXTID:     return this->Receive_CLIENT_INFO_EXTID(p);
    00169     case PACKET_CONTENT_CLIENT_INFO_EXTID_MD5: return this->Receive_CLIENT_INFO_EXTID_MD5(p);
    00170     case PACKET_CONTENT_SERVER_INFO:           return this->Receive_SERVER_INFO(p);
    00171     case PACKET_CONTENT_CLIENT_CONTENT:        return this->Receive_CLIENT_CONTENT(p);
    00172     case PACKET_CONTENT_SERVER_CONTENT:        return this->Receive_SERVER_CONTENT(p);
    00173
    00174     default:
    00175       if (this->HasClientQuit()) {
    00176         DEBUG(net, 0, "[tcp/content] received invalid packet type %d from %s", type, this->client_addr.GetAddressAsString());
    00177       } else {
    00178         DEBUG(net, 0, "[tcp/content] received illegal packet from %s", this->client_addr.GetAddressAsString());
    00179       }
    00180       return false;
    00181   }
    00182 }
    00183
    00188 bool NetworkContentSocketHandler::ReceivePackets()
    00189 {
    00190   /*
    00191    * We read only a few of the packets. This as receiving packets can be expensive
    00192    * due to the re-resolving of the parent/child relations and checking the toggle
    00193    * state of all bits. We cannot do this all in one go, as we want to show the
    00194    * user what we already received. Otherwise, it can take very long before any
    00195    * progress is shown to the end user that something has been received.
    00196    * It is also the case that we request extra content from the content server in
    00197    * case there is an unknown (in the content list) piece of content. These will
    00198    * come in after the main lists have been requested. As a result, we won't be
    00199    * getting everything reliably in one batch. Thus, we need to make subsequent
    00200    * updates in that case as well.
    00201    *
    00202    * As a result, we simple handle an arbitrary number of packets in one cycle,
    00203    * and let the rest be handled in subsequent cycles. These are ran, almost,
    00204    * immediately after this cycle so in speed it does not matter much, except
    00205    * that the user inferface will appear better responding.
    00206    *
    00207    * What arbitrary number to choose is the ultimate question though.
    00208    */
    00209   Packet *p;
    00210   static const int MAX_PACKETS_TO_RECEIVE = 42;
    00211   int i = MAX_PACKETS_TO_RECEIVE;
    00212   while (--i != 0 && (p = this->ReceivePacket()) != NULL) {
    00213     bool cont = this->HandlePacket(p);
    00214     delete p;
    00215     if (!cont) return true;
    00216   }
    00217
    00218   return i != MAX_PACKETS_TO_RECEIVE - 1;
    00219 }
    00220
    00221
    00227 bool NetworkContentSocketHandler::ReceiveInvalidPacket(PacketContentType type)
    00228 {
    00229   DEBUG(net, 0, "[tcp/content] received illegal packet type %d from %s", type, this->client_addr.GetAddressAsString());
    00230   return false;
    00231 }
    00232
    00233 bool NetworkContentSocketHandler::Receive_CLIENT_INFO_LIST(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_LIST); }
    00234 bool NetworkContentSocketHandler::Receive_CLIENT_INFO_ID(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_ID); }
    00235 bool NetworkContentSocketHandler::Receive_CLIENT_INFO_EXTID(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_EXTID); }
    00236 bool NetworkContentSocketHandler::Receive_CLIENT_INFO_EXTID_MD5(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_EXTID_MD5); }
    00237 bool NetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_INFO); }
    00238 bool NetworkContentSocketHandler::Receive_CLIENT_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_CONTENT); }
    00239 bool NetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_CONTENT); }
    00240
    00241 #ifndef OPENTTD_MSU
    00242
    00247 Subdirectory GetContentInfoSubDir(ContentType type)
    00248 {
    00249   switch (type) {
    00250     default: return NO_DIRECTORY;
    00251     case CONTENT_TYPE_AI:           return AI_DIR;
    00252     case CONTENT_TYPE_AI_LIBRARY:   return AI_LIBRARY_DIR;
    00253     case CONTENT_TYPE_GAME:         return GAME_DIR;
    00254     case CONTENT_TYPE_GAME_LIBRARY: return GAME_LIBRARY_DIR;
    00255     case CONTENT_TYPE_NEWGRF:       return NEWGRF_DIR;
    00256
    00257     case CONTENT_TYPE_BASE_GRAPHICS:
    00258     case CONTENT_TYPE_BASE_SOUNDS:
    00259     case CONTENT_TYPE_BASE_MUSIC:
    00260       return BASESET_DIR;
    00261
    00262     case CONTENT_TYPE_SCENARIO:     return SCENARIO_DIR;
    00263     case CONTENT_TYPE_HEIGHTMAP:    return HEIGHTMAP_DIR;
    00264   }
    00265 }
    00266 #endif /* OPENTTD_MSU */
    00267
    00268 #endif /* ENABLE_NETWORK */