summaryrefslogtreecommitdiff
path: root/src/network/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/core')
-rw-r--r--src/network/core/config.h3
-rw-r--r--src/network/core/tcp_content.cpp136
-rw-r--r--src/network/core/tcp_content.h208
3 files changed, 347 insertions, 0 deletions
diff --git a/src/network/core/config.h b/src/network/core/config.h
index c41190cce..e2fbb5e3a 100644
--- a/src/network/core/config.h
+++ b/src/network/core/config.h
@@ -9,11 +9,14 @@
/** DNS hostname of the masterserver */
#define NETWORK_MASTER_SERVER_HOST "master.openttd.org"
+/** DNS hostname of the content server */
+#define NETWORK_CONTENT_SERVER_HOST "content.openttd.org"
/** Message sent to the masterserver to 'identify' this client as OpenTTD */
#define NETWORK_MASTER_SERVER_WELCOME_MESSAGE "OpenTTDRegister"
enum {
NETWORK_MASTER_SERVER_PORT = 3978, ///< The default port of the master server (UDP)
+ NETWORK_CONTENT_SERVER_PORT = 3978, ///< The default port of the content server (TCP)
NETWORK_DEFAULT_PORT = 3979, ///< The default port of the game server (TCP & UDP)
NETWORK_DEFAULT_DEBUGLOG_PORT = 3982, ///< The default port debug-log is sent too (TCP)
diff --git a/src/network/core/tcp_content.cpp b/src/network/core/tcp_content.cpp
new file mode 100644
index 000000000..32054a1e2
--- /dev/null
+++ b/src/network/core/tcp_content.cpp
@@ -0,0 +1,136 @@
+/* $Id$ */
+
+/**
+ * @file tcp_content.cpp Basic functions to receive and send Content packets.
+ */
+
+#ifdef ENABLE_NETWORK
+
+#include "../../stdafx.h"
+#include "../../debug.h"
+#include "tcp_content.h"
+
+ContentInfo::ContentInfo()
+{
+ memset(this, 0, sizeof(*this));
+}
+
+ContentInfo::~ContentInfo()
+{
+ free(this->dependencies);
+ free(this->tags);
+}
+
+size_t ContentInfo::Size() const
+{
+ size_t len = 0;
+ for (uint i = 0; i < this->tag_count; i++) len += strlen(this->tags[i]) + 1;
+
+ /* The size is never larger than the content info size plus the size of the
+ * tags and dependencies */
+ return sizeof(*this) +
+ sizeof(this->dependency_count) +
+ sizeof(*this->dependencies) * this->dependency_count;
+}
+
+bool ContentInfo::IsSelected() const
+{
+ switch (this->state) {
+ case ContentInfo::SELECTED:
+ case ContentInfo::AUTOSELECTED:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool ContentInfo::IsValid() const
+{
+ return this->state < ContentInfo::INVALID && this->type >= CONTENT_TYPE_BEGIN && this->type < CONTENT_TYPE_END;
+}
+
+NetworkRecvStatus NetworkContentSocketHandler::CloseConnection()
+{
+ this->has_quit = true;
+ return NETWORK_RECV_STATUS_OKAY;
+}
+
+void NetworkContentSocketHandler::Close()
+{
+ CloseConnection();
+ if (this->sock == INVALID_SOCKET) return;
+
+ closesocket(this->sock);
+ this->sock = INVALID_SOCKET;
+}
+
+/**
+ * Defines a simple (switch) case for each network packet
+ * @param type the packet type to create the case for
+ */
+#define CONTENT_COMMAND(type) case type: return this->NetworkPacketReceive_ ## type ## _command(p); break;
+
+/**
+ * Handle an incoming packets by sending it to the correct function.
+ * @param p the received packet
+ */
+bool NetworkContentSocketHandler::HandlePacket(Packet *p)
+{
+ PacketContentType type = (PacketContentType)p->Recv_uint8();
+
+ switch (this->HasClientQuit() ? PACKET_CONTENT_END : type) {
+ CONTENT_COMMAND(PACKET_CONTENT_CLIENT_INFO_LIST);
+ CONTENT_COMMAND(PACKET_CONTENT_CLIENT_INFO_ID);
+ CONTENT_COMMAND(PACKET_CONTENT_CLIENT_INFO_EXTID);
+ CONTENT_COMMAND(PACKET_CONTENT_CLIENT_INFO_EXTID_MD5);
+ CONTENT_COMMAND(PACKET_CONTENT_SERVER_INFO);
+ CONTENT_COMMAND(PACKET_CONTENT_CLIENT_CONTENT);
+ CONTENT_COMMAND(PACKET_CONTENT_SERVER_CONTENT);
+
+ default:
+ if (this->HasClientQuit()) {
+ DEBUG(net, 0, "[tcp/content] received invalid packet type %d from %s:%d", type, inet_ntoa(this->client_addr.sin_addr), ntohs(this->client_addr.sin_port));
+ } else {
+ DEBUG(net, 0, "[tcp/content] received illegal packet from %s:%d", inet_ntoa(this->client_addr.sin_addr), ntohs(this->client_addr.sin_port));
+ }
+ return false;
+ }
+}
+
+/**
+ * Receive a packet at UDP level
+ */
+void NetworkContentSocketHandler::Recv_Packets()
+{
+ Packet *p;
+ NetworkRecvStatus res;
+ while ((p = this->Recv_Packet(&res)) != NULL) {
+ bool cont = HandlePacket(p);
+ delete p;
+ if (!cont) return;
+ }
+}
+
+/**
+ * Create stub implementations for all receive commands that only
+ * show a warning that the given command is not available for the
+ * socket where the packet came from.
+ * @param type the packet type to create the stub for
+ */
+#define DEFINE_UNAVAILABLE_CONTENT_RECEIVE_COMMAND(type) \
+bool NetworkContentSocketHandler::NetworkPacketReceive_## type ##_command(Packet *p) { \
+ DEBUG(net, 0, "[tcp/content] received illegal packet type %d from %s:%d", \
+ type, inet_ntoa(this->client_addr.sin_addr), ntohs(this->client_addr.sin_port)); \
+ return false; \
+}
+
+DEFINE_UNAVAILABLE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_CLIENT_INFO_LIST);
+DEFINE_UNAVAILABLE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_CLIENT_INFO_ID);
+DEFINE_UNAVAILABLE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_CLIENT_INFO_EXTID);
+DEFINE_UNAVAILABLE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_CLIENT_INFO_EXTID_MD5);
+DEFINE_UNAVAILABLE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_SERVER_INFO);
+DEFINE_UNAVAILABLE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_CLIENT_CONTENT);
+DEFINE_UNAVAILABLE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_SERVER_CONTENT);
+
+#endif /* ENABLE_NETWORK */
diff --git a/src/network/core/tcp_content.h b/src/network/core/tcp_content.h
new file mode 100644
index 000000000..5b7c2b850
--- /dev/null
+++ b/src/network/core/tcp_content.h
@@ -0,0 +1,208 @@
+/* $Id$ */
+
+/**
+ * @file tcp_content.h Basic functions to receive and send TCP packets to/from the content server.
+ */
+
+#ifndef NETWORK_CORE_CONTENT_H
+#define NETWORK_CORE_CONTENT_H
+
+#ifdef ENABLE_NETWORK
+
+#include "os_abstraction.h"
+#include "tcp.h"
+#include "packet.h"
+#include "../../debug.h"
+
+/** The values in the enum are important; they are used as database 'keys' */
+enum ContentType {
+ CONTENT_TYPE_BEGIN = 1, ///< Helper to mark the begin of the types
+ CONTENT_TYPE_BASE_GRAPHICS = 1, ///< The content consists of base graphics
+ CONTENT_TYPE_NEWGRF = 2, ///< The content consists of a NewGRF
+ CONTENT_TYPE_AI = 3, ///< The content consists of an AI
+ CONTENT_TYPE_AI_LIBRARY = 4, ///< The content consists of an AI library
+ CONTENT_TYPE_SCENARIO = 5, ///< The content consists of a scenario
+ CONTENT_TYPE_HEIGHTMAP = 6, ///< The content consists of a heightmap
+ CONTENT_TYPE_END, ///< Helper to mark the end of the types
+};
+
+/** Enum with all types of TCP content packets. The order MUST not be changed **/
+enum PacketContentType {
+ PACKET_CONTENT_CLIENT_INFO_LIST, ///< Queries the content server for a list of info of a given content type
+ PACKET_CONTENT_CLIENT_INFO_ID, ///< Queries the content server for information about a list of internal IDs
+ PACKET_CONTENT_CLIENT_INFO_EXTID, ///< Queries the content server for information about a list of external IDs
+ PACKET_CONTENT_CLIENT_INFO_EXTID_MD5, ///< Queries the content server for information about a list of external IDs and MD5
+ PACKET_CONTENT_SERVER_INFO, ///< Reply of content server with information about content
+ PACKET_CONTENT_CLIENT_CONTENT, ///< Request a content file given an internal ID
+ PACKET_CONTENT_SERVER_CONTENT, ///< Reply with the content of the given ID
+ PACKET_CONTENT_END ///< Must ALWAYS be on the end of this list!! (period)
+};
+
+#define DECLARE_CONTENT_RECEIVE_COMMAND(type) virtual bool NetworkPacketReceive_## type ##_command(Packet *p)
+#define DEF_CONTENT_RECEIVE_COMMAND(cls, type) bool cls ##NetworkContentSocketHandler::NetworkPacketReceive_ ## type ## _command(Packet *p)
+
+enum ContentID {
+ INVALID_CONTENT_ID = UINT32_MAX
+};
+
+/** Container for all important information about a piece of content. */
+struct ContentInfo {
+ enum State {
+ UNSELECTED, ///< The content has not been selected
+ SELECTED, ///< The content has been manually selected
+ AUTOSELECTED, ///< The content has been selected as dependency
+ ALREADY_HERE, ///< The content is already at the client side
+ DOES_NOT_EXIST, ///< The content does not exist in the content system
+ INVALID ///< The content's invalid
+ };
+
+ ContentType type; ///< Type of content
+ ContentID id; ///< Unique (server side) ID for the content
+ uint32 filesize; ///< Size of the file
+ char filename[48]; ///< Filename (for the .tar.gz; only valid on download)
+ char name[32]; ///< Name of the content
+ char version[16]; ///< Version of the content
+ char url[64]; ///< URL related to the content
+ char description[512]; ///< Description of the content
+ uint32 unique_id; ///< Unique ID; either GRF ID or shortname
+ byte md5sum[16]; ///< The MD5 checksum
+ uint8 dependency_count; ///< Number of dependencies
+ ContentID *dependencies; ///< Malloced array of dependencies (unique server side ids)
+ uint8 tag_count; ///< Number of tags
+ char (*tags)[32]; ///< Malloced array of tags (strings)
+ State state; ///< Whether the content info is selected (for download)
+ bool update; ///< This item is an update
+
+ /** Clear everything in the struct */
+ ContentInfo();
+
+ /** Free everything allocated */
+ ~ContentInfo();
+
+ /**
+ * Get the size of the data as send over the network.
+ * @return the size.
+ */
+ size_t Size() const;
+
+ /**
+ * Is the state either selected or autoselected?
+ * @return true iff that's the case
+ */
+ bool IsSelected() const;
+
+ /**
+ * Is the information from this content info valid?
+ * @return true iff it's valid
+ */
+ bool IsValid() const;
+};
+
+/** Base socket handler for all Content TCP sockets */
+class NetworkContentSocketHandler : public NetworkTCPSocketHandler {
+protected:
+ struct sockaddr_in client_addr; ///< The address we're connected to.
+ NetworkRecvStatus CloseConnection();
+ void Close();
+
+ /**
+ * Client requesting a list of content info:
+ * byte type
+ * uint32 openttd version
+ */
+ DECLARE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_CLIENT_INFO_LIST);
+
+ /**
+ * Client requesting a list of content info:
+ * uint16 count of ids
+ * uint32 id (count times)
+ */
+ DECLARE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_CLIENT_INFO_ID);
+
+ /**
+ * Client requesting a list of content info based on an external
+ * 'unique' id; GRF ID for NewGRFS, shortname and for base
+ * graphics and AIs.
+ * Scenarios and AI libraries are not supported
+ * uint8 count of requests
+ * for each request:
+ * uint8 type
+ * unique id (uint32)
+ */
+ DECLARE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_CLIENT_INFO_EXTID);
+
+ /**
+ * Client requesting a list of content info based on an external
+ * 'unique' id; GRF ID + MD5 checksum for NewGRFS, shortname and
+ * xor-ed MD5 checsums for base graphics and AIs.
+ * Scenarios and AI libraries are not supported
+ * uint8 count of requests
+ * for each request:
+ * uint8 type
+ * unique id (uint32)
+ * md5 (16 bytes)
+ */
+ DECLARE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_CLIENT_INFO_EXTID_MD5);
+
+ /**
+ * Server sending list of content info:
+ * byte type (invalid ID == does not exist)
+ * uint32 id
+ * uint32 file_size
+ * string name (max 32 characters)
+ * string version (max 16 characters)
+ * uint32 unique id
+ * uint8 md5sum (16 bytes)
+ * uint8 dependency count
+ * uint32 unique id of dependency (dependency count times)
+ * uint8 tag count
+ * string tag (max 32 characters for tag count times)
+ */
+ DECLARE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_SERVER_INFO);
+
+ /**
+ * Client requesting the actual content:
+ * uint16 count of unique ids
+ * uint32 unique id (count times)
+ */
+ DECLARE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_CLIENT_CONTENT);
+
+ /**
+ * Server sending list of content info:
+ * uint32 unique id
+ * uint32 file size (0 == does not exist)
+ * string file name (max 48 characters)
+ * After this initial packet, packets with the actual data are send using
+ * the same packet type.
+ */
+ DECLARE_CONTENT_RECEIVE_COMMAND(PACKET_CONTENT_SERVER_CONTENT);
+
+ /**
+ * Handle the given packet, i.e. pass it to the right
+ * parser receive command.
+ * @param p the packet to handle
+ * @return true if we should immediatelly handle further packets, false otherwise
+ */
+ bool HandlePacket(Packet *p);
+public:
+ /**
+ * Create a new cs socket handler for a given cs
+ * @param s the socket we are connected with
+ * @param sin IP etc. of the client
+ */
+ NetworkContentSocketHandler(SOCKET s, const struct sockaddr_in *sin) :
+ NetworkTCPSocketHandler(s),
+ client_addr(*sin)
+ {
+ }
+
+ /** On destructing of this class, the socket needs to be closed */
+ virtual ~NetworkContentSocketHandler() { this->Close(); }
+
+ /** Do the actual receiving of packets. */
+ void Recv_Packets();
+};
+
+#endif /* ENABLE_NETWORK */
+
+#endif /* NETWORK_CORE_CONTENT_H */