(svn r18994) -Change: content mirroring support (based on work by TrueBrain).

This commit is contained in:
rubidium 2010-02-03 18:42:23 +00:00
parent c75f19f40b
commit 2db44fc18e
11 changed files with 675 additions and 5 deletions

View File

@ -3415,6 +3415,14 @@
RelativePath=".\..\src\network\core\tcp_game.h"
>
</File>
<File
RelativePath=".\..\src\network\core\tcp_http.cpp"
>
</File>
<File
RelativePath=".\..\src\network\core\tcp_http.h"
>
</File>
<File
RelativePath=".\..\src\network\core\udp.cpp"
>

View File

@ -3412,6 +3412,14 @@
RelativePath=".\..\src\network\core\tcp_game.h"
>
</File>
<File
RelativePath=".\..\src\network\core\tcp_http.cpp"
>
</File>
<File
RelativePath=".\..\src\network\core\tcp_http.h"
>
</File>
<File
RelativePath=".\..\src\network\core\udp.cpp"
>

View File

@ -803,6 +803,8 @@ network/core/tcp_content.cpp
network/core/tcp_content.h
network/core/tcp_game.cpp
network/core/tcp_game.h
network/core/tcp_http.cpp
network/core/tcp_http.h
network/core/udp.cpp
network/core/udp.h

View File

@ -18,12 +18,17 @@
#define NETWORK_MASTER_SERVER_HOST "master.openttd.org"
/** DNS hostname of the content server */
#define NETWORK_CONTENT_SERVER_HOST "content.openttd.org"
/** DNS hostname of the HTTP-content mirror server */
#define NETWORK_CONTENT_MIRROR_HOST "binaries.openttd.org"
/** URL of the HTTP mirror system */
#define NETWORK_CONTENT_MIRROR_URL "/bananas"
/** 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_CONTENT_MIRROR_PORT = 80, ///< The default port of the content mirror (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)

View File

@ -0,0 +1,317 @@
/* $Id$ */
/*
* This file is part of OpenTTD.
* 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.
* 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.
* 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/>.
*/
/**
* @file tcp_http.cpp Basic functions to receive and send HTTP TCP packets.
*/
#ifdef ENABLE_NETWORK
#include "../../stdafx.h"
#include "../../debug.h"
#include "../../rev.h"
#include "../network_func.h"
#include "tcp.h"
#include "tcp_http.h"
/** List of open HTTP connections. */
static SmallVector<NetworkHTTPSocketHandler *, 1> _http_connections;
NetworkHTTPSocketHandler::NetworkHTTPSocketHandler(SOCKET s,
HTTPCallback *callback, const char *host, const char *url,
const char *data, int depth) :
NetworkSocketHandler(),
recv_pos(0),
recv_length(0),
callback(callback),
data(data),
redirect_depth(depth),
sock(s)
{
int bufferSize = strlen(url) + strlen(host) + strlen(_openttd_revision) + (data == NULL ? 0 : strlen(data)) + 128;
char *buffer = AllocaM(char, bufferSize);
DEBUG(net, 7, "[tcp/http] requesting %s%s", host, url);
if (data != NULL) {
seprintf(buffer, buffer + bufferSize - 1, "POST %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: OpenTTD/%s\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s\r\n", url, host, _openttd_revision, (int)strlen(data), data);
} else {
seprintf(buffer, buffer + bufferSize - 1, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: OpenTTD/%s\r\n\r\n", url, host, _openttd_revision);
}
ssize_t size = strlen(buffer);
ssize_t res = send(this->sock, (const char*)buffer, size, 0);
if (res != size) {
/* Sending all data failed. Socket can't handle this little bit
* of information? Just fall back to the old system! */
this->callback->OnFailure();
delete this;
}
*_http_connections.Append() = this;
}
NetworkHTTPSocketHandler::~NetworkHTTPSocketHandler()
{
this->CloseConnection();
if (this->sock != INVALID_SOCKET) closesocket(this->sock);
this->sock = INVALID_SOCKET;
free((void*)this->data);
}
NetworkRecvStatus NetworkHTTPSocketHandler::CloseConnection(bool error)
{
NetworkSocketHandler::CloseConnection(error);
return NETWORK_RECV_STATUS_OKAY;
}
/**
* Helper to simplify the error handling.
* @param msg the error message to show.
*/
#define return_error(msg) { DEBUG(net, 0, msg); return -1; }
static const char * const NEWLINE = "\r\n"; ///< End of line marker
static const char * const END_OF_HEADER = "\r\n\r\n"; ///< End of header marker
static const char * const HTTP_1_0 = "HTTP/1.0 "; ///< Preamble for HTTP 1.0 servers
static const char * const HTTP_1_1 = "HTTP/1.1 "; ///< Preamble for HTTP 1.1 servers
static const char * const CONTENT_LENGTH = "Content-Length: "; ///< Header for the length of the content
static const char * const LOCATION = "Location: "; ///< Header for location
/**
* Handle the header of a HTTP reply.
* @return amount of data to continue downloading.
* > 0: we need to download N bytes.
* = 0: we're being redirected.
* < 0: an error occured. Downloading failed.
* @note if an error occured the header might not be in its
* original state. No effort is undertaken to bring
* the header in its original state.
*/
int NetworkHTTPSocketHandler::HandleHeader()
{
assert(strlen(HTTP_1_0) == strlen(HTTP_1_1));
assert(strstr(this->recv_buffer, END_OF_HEADER) != NULL);
/* We expect a HTTP/1.[01] reply */
if (strncmp(this->recv_buffer, HTTP_1_0, strlen(HTTP_1_0)) != 0 &&
strncmp(this->recv_buffer, HTTP_1_1, strlen(HTTP_1_1)) != 0) {
return_error("[tcp/http] received invalid HTTP reply");
}
char *status = this->recv_buffer + strlen(HTTP_1_0);
if (strncmp(status, "200", 3) == 0) {
/* We are going to receive a document. */
/* Get the length of the document to receive */
char *length = strcasestr(this->recv_buffer, CONTENT_LENGTH);
if (length == NULL) return_error("[tcp/http] missing 'content-length' header");
/* Skip the header */
length += strlen(CONTENT_LENGTH);
/* Search the end of the line. This is safe because the header will
* always end with two newlines. */
char *end_of_line = strstr(length, NEWLINE);
/* Read the length */
*end_of_line = '\0';
int len = atoi(length);
/* Restore the header. */
*end_of_line = '\r';
/* Make sure we're going to download at least something;
* zero sized files are, for OpenTTD's purposes, always
* wrong. You can't have gzips of 0 bytes! */
if (len == 0) return_error("[tcp/http] refusing to download 0 bytes");
DEBUG(net, 7, "[tcp/http] downloading %i bytes", len);
return len;
}
if (strncmp(status, "301", 3) != 0 &&
strncmp(status, "302", 3) != 0 &&
strncmp(status, "303", 3) != 0 &&
strncmp(status, "307", 3) != 0) {
/* We are not going to be redirected :(. */
/* Search the end of the line. This is safe because the header will
* always end with two newlines. */
*strstr(status, NEWLINE) = '\0';
DEBUG(net, 0, "[tcp/http] unhandled status reply %s", status);
return -1;
}
if (this->redirect_depth == 5) return_error("[tcp/http] too many redirects, looping redirects?");
/* Redirect to other URL */
char *uri = strcasestr(this->recv_buffer, LOCATION);
if (uri == NULL) return_error("[tcp/http] missing 'location' header for redirect");
uri += strlen(LOCATION);
/* Search the end of the line. This is safe because the header will
* always end with two newlines. */
char *end_of_line = strstr(uri, NEWLINE);
*end_of_line = '\0';
DEBUG(net, 6, "[tcp/http] redirecting to %s", uri);
int ret = NetworkHTTPSocketHandler::Connect(uri, this->callback, this->data, this->redirect_depth + 1);
if (ret != 0) return ret;
/* We've relinguished control of data now. */
this->data = NULL;
/* Restore the header. */
*end_of_line = '\r';
return 0;
}
/*static */ int NetworkHTTPSocketHandler::Connect(char *uri, HTTPCallback *callback, const char *data, int depth)
{
char *hname = strstr(uri, "://");
if (hname == NULL) return_error("[tcp/http] invalid location");
hname += 3;
char *url = strchr(hname, '/');
if (url == NULL) return_error("[tcp/http] invalid location");
*url = '\0';
/* Fetch the hostname, and possible port number. */
const char *company = NULL;
const char *port = NULL;
ParseConnectionString(&company, &port, hname);
if (company != NULL) return_error("[tcp/http] invalid hostname");
NetworkAddress address(hname, port == NULL ? 80 : atoi(port));
/* Restore the URL. */
*url = '/';
new NetworkHTTPContentConnecter(address, callback, url, data, depth);
return 0;
}
#undef return_error
/**
* Handle receiving of HTTP data.
* @return state of the receival of HTTP data.
* > 0: we need more cycles for downloading
* = 0: we are done downloading
* < 0: we have hit an error
*/
int NetworkHTTPSocketHandler::Receive()
{
for (;;) {
ssize_t res = recv(this->sock, (char *)this->recv_buffer + this->recv_pos, lengthof(this->recv_buffer) - this->recv_pos, 0);
if (res == -1) {
int err = GET_LAST_ERROR();
if (err != EWOULDBLOCK) {
/* Something went wrong... (104 is connection reset by peer) */
if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
return -1;
}
/* Connection would block, so stop for now */
return 1;
}
/* No more data... did we get everything we wanted? */
if (res == 0) {
if (this->recv_length != 0) return -1;
this->callback->OnReceiveData(NULL, 0);
return 0;
}
/* Wait till we read the end-of-header identifier */
if (this->recv_length == 0) {
int read = this->recv_pos + res;
int end = min(read, lengthof(this->recv_buffer) - 1);
/* Do a 'safe' search for the end of the header. */
char prev = this->recv_buffer[end];
this->recv_buffer[end] = '\0';
char *end_of_header = strstr(this->recv_buffer, END_OF_HEADER);
this->recv_buffer[end] = prev;
if (end_of_header == NULL) {
if (read == lengthof(this->recv_buffer)) {
DEBUG(net, 0, "[tcp/http] header too big");
return -1;
}
this->recv_pos = read;
} else {
int ret = this->HandleHeader();
if (ret <= 0) return ret;
this->recv_length = ret;
end_of_header += strlen(END_OF_HEADER);
int len = min(read - (end_of_header - this->recv_buffer), res);
if (len != 0) {
this->callback->OnReceiveData(end_of_header, len);
this->recv_length -= len;
}
this->recv_pos = 0;
}
} else {
res = min(this->recv_length, res);
/* Receive whatever we're expecting. */
this->callback->OnReceiveData(this->recv_buffer, res);
this->recv_length -= res;
}
}
}
/* static */ void NetworkHTTPSocketHandler::HTTPReceive()
{
/* No connections, just bail out. */
if (_http_connections.Length() == 0) return;
fd_set read_fd;
struct timeval tv;
FD_ZERO(&read_fd);
for (NetworkHTTPSocketHandler **iter = _http_connections.Begin(); iter < _http_connections.End(); iter++) {
FD_SET((*iter)->sock, &read_fd);
}
tv.tv_sec = tv.tv_usec = 0; // don't block at all.
#if !defined(__MORPHOS__) && !defined(__AMIGA__)
int n = select(FD_SETSIZE, &read_fd, NULL, NULL, &tv);
#else
int n = WaitSelect(FD_SETSIZE, &read_fd, NULL, NULL, &tv, NULL);
#endif
if (n == -1) return;
for (NetworkHTTPSocketHandler **iter = _http_connections.Begin(); iter < _http_connections.End(); /* nothing */) {
NetworkHTTPSocketHandler *cur = *iter;
if (FD_ISSET(cur->sock, &read_fd)) {
int ret = cur->Receive();
/* First send the failure. */
if (ret < 0) cur->callback->OnFailure();
if (ret <= 0) {
/* Then... the connection can be closed */
cur->CloseConnection();
_http_connections.Erase(iter);
delete cur;
continue;
}
}
iter++;
}
}
#endif /* ENABLE_NETWORK */

143
src/network/core/tcp_http.h Normal file
View File

@ -0,0 +1,143 @@
/* $Id$ */
/*
* This file is part of OpenTTD.
* 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.
* 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.
* 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/>.
*/
/**
* @file tcp_http.h Basic functions to receive and send HTTP TCP packets.
*/
#ifndef NETWORK_CORE_TCP_HTTP_H
#define NETWORK_CORE_TCP_HTTP_H
#include "address.h"
#ifdef ENABLE_NETWORK
/** Callback for when the HTTP handler has something to tell us. */
struct HTTPCallback {
/**
* An error has occured and the connection has been closed.
* @note HTTP socket handler is closed/freed.
*/
virtual void OnFailure() = 0;
/**
* We're receiving data.
* @param data the received data, NULL when all data has been received.
* @param length the amount of received data, 0 when all data has been received.
* @note When NULL is sent the HTTP socket handler is closed/freed.
*/
virtual void OnReceiveData(const char *data, size_t length) = 0;
};
/** Base socket handler for HTTP traffic. */
class NetworkHTTPSocketHandler : public NetworkSocketHandler {
private:
char recv_buffer[4096]; ///< Partially received message.
int recv_pos; ///< Current position in buffer.
int recv_length; ///< Length of the data still retrieving.
HTTPCallback *callback; ///< The callback to call for the incoming data.
const char *data; ///< The (POST) data we might want to forward (to a redirect).
int redirect_depth; ///< The depth of the redirection.
int HandleHeader();
int Receive();
public:
SOCKET sock; ///< The socket currently connected to
/**
* Whether this socket is currently bound to a socket.
* @return true when the socket is bound, false otherwise
*/
bool IsConnected() const
{
return this->sock != INVALID_SOCKET;
}
virtual NetworkRecvStatus CloseConnection(bool error = true);
/**
* Start the querying
* @param sock the socket of this connection
* @param callback the callback for HTTP retrieval
* @param url the url at the server
* @param data the data to send
* @param depth the depth (redirect recursion) of the queries
*/
NetworkHTTPSocketHandler(SOCKET sock, HTTPCallback *callback,
const char *host, const char *url, const char *data, int depth);
/** Free whatever needs to be freed. */
~NetworkHTTPSocketHandler();
/**
* Connect to the given URI.
* @param uri the URI to connect to.
* @param callback the callback to send data back on.
* @param data the data we want to send (as POST).
* @param depth the recursion/redirect depth.
*/
static int Connect(char *uri, HTTPCallback *callback,
const char *data = NULL, int depth = 0);
/**
* Do the receiving for all HTTP connections.
*/
static void HTTPReceive();
};
/** Connect with a HTTP server and do ONE query. */
class NetworkHTTPContentConnecter : TCPConnecter {
HTTPCallback *callback; ///< Callback to tell that we received some data (or won't).
const char *url; ///< The URL we want to get at the server.
const char *data; ///< The data to send
int depth; ///< How far we have recursed
public:
/**
* Start the connecting.
* @param address the address to connect to
* @param callback the callback for HTTP retrieval
* @param url the url at the server
* @param data the data to send
* @param depth the depth (redirect recursion) of the queries
*/
NetworkHTTPContentConnecter(const NetworkAddress &address,
HTTPCallback *callback, const char *url,
const char *data = NULL, int depth = 0) :
TCPConnecter(address),
callback(callback),
url(strdup(url)),
data(data),
depth(depth)
{
}
/** Free all our allocated data. */
~NetworkHTTPContentConnecter()
{
free((void*)this->url);
}
virtual void OnFailure()
{
this->callback->OnFailure();
free((void*)this->data);
}
virtual void OnConnect(SOCKET s)
{
new NetworkHTTPSocketHandler(s, this->callback, this->address.GetHostname(), this->url, this->data, this->depth);
/* We've relinguished control of data now. */
this->data = NULL;
}
};
#endif /* ENABLE_NETWORK */
#endif /* NETWORK_CORE_HTTP_H */

View File

@ -1050,6 +1050,7 @@ void NetworkUDPGameLoop()
{
_network_content_client.SendReceive();
TCPConnecter::CheckCallbacks();
NetworkHTTPSocketHandler::HTTPReceive();
if (_network_udp_server) {
_udp_server_socket->ReceivePackets();

View File

@ -18,6 +18,7 @@
#include "../gui.h"
#include "../variables.h"
#include "../base_media_base.h"
#include "../settings_type.h"
#include "network_content.h"
#include "table/strings.h"
@ -251,7 +252,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo
}
}
void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uint &bytes)
void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uint &bytes, bool fallback)
{
bytes = 0;
@ -269,8 +270,41 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uin
/* If there's nothing to download, do nothing. */
if (files == 0) return;
uint count = files;
ContentID *content_ids = content.Begin();
if (_settings_client.network.no_http_content_downloads || fallback) {
this->DownloadSelectedContentFallback(content);
} else {
this->DownloadSelectedContentHTTP(content);
}
}
void ClientNetworkContentSocketHandler::DownloadSelectedContentHTTP(const ContentIDList &content)
{
uint count = content.Length();
/* Allocate memory for the whole request.
* Requests are "id\nid\n..." (as strings), so assume the maximum ID,
* which is uint32 so 10 characters long. Then the newlines and
* multiply that all with the count and then add the '\0'. */
uint bytes = (10 + 1) * count + 1;
char *content_request = MallocT<char>(bytes);
const char *lastof = content_request + bytes - 1;
char *p = content_request;
for (const ContentID *id = content.Begin(); id != content.End(); id++) {
p += seprintf(p, lastof, "%d\n", *id);
}
this->http_response_index = -1;
NetworkAddress address(NETWORK_CONTENT_MIRROR_HOST, NETWORK_CONTENT_MIRROR_PORT);
new NetworkHTTPContentConnecter(address, this, NETWORK_CONTENT_MIRROR_URL, content_request);
/* NetworkHTTPContentConnecter takes over freeing of content_request! */
}
void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const ContentIDList &content)
{
uint count = content.Length();
const ContentID *content_ids = content.Begin();
this->Connect();
while (count > 0) {
@ -451,6 +485,146 @@ void ClientNetworkContentSocketHandler::AfterDownload()
}
}
/* Also called to just clean up the mess. */
void ClientNetworkContentSocketHandler::OnFailure()
{
/* If we fail, download the rest via the 'old' system. */
uint files, bytes;
this->DownloadSelectedContent(files, bytes, true);
this->http_response.Reset();
this->http_response_index = -2;
if (this->curFile != NULL) {
fclose(this->curFile);
this->curFile = NULL;
}
}
void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t length)
{
assert(data == NULL || length != 0);
/* Ignore any latent data coming from a connection we closed. */
if (this->http_response_index == -2) return;
if (this->http_response_index == -1) {
if (data != NULL) {
/* Append the rest of the response. */
memcpy(this->http_response.Append(length), data, length);
return;
} else {
/* Make sure the response is properly terminated. */
*this->http_response.Append() = '\0';
/* And prepare for receiving the rest of the data. */
this->http_response_index = 0;
}
}
if (data != NULL) {
/* We have data, so write it to the file. */
if (fwrite(data, 1, length, this->curFile) != length) {
/* Writing failed somehow, let try via the old method. */
this->OnFailure();
} else {
/* Just received the data. */
this->OnDownloadProgress(this->curInfo, (uint)length);
}
/* Nothing more to do now. */
return;
}
if (this->curFile != NULL) {
/* We've finished downloading a file. */
this->AfterDownload();
}
if ((uint)this->http_response_index >= this->http_response.Length()) {
/* It's not a real failure, but if there's
* nothing more to download it helps with
* cleaning up the stuff we allocated. */
this->OnFailure();
return;
}
delete this->curInfo;
/* When we haven't opened a file this must be our first packet with metadata. */
this->curInfo = new ContentInfo;
/** Check p for not being null and return calling OnFailure if that's not the case. */
#define check(p) { if ((p) == NULL) { this->OnFailure(); return; } }
/** Check p for not being null and then terminate, or return calling OnFailure. */
#define check_and_terminate(p) { check(p); *(p) = '\0'; }
for (;;) {
char *str = this->http_response.Begin() + this->http_response_index;
char *p = strchr(str, '\n');
check_and_terminate(p);
/* Update the index for the next one */
this->http_response_index += strlen(str) + 1;
/* Read the ID */
p = strchr(str, ',');
check_and_terminate(p);
this->curInfo->id = (ContentID)atoi(str);
/* Read the type */
str = p + 1;
p = strchr(str, ',');
check_and_terminate(p);
this->curInfo->type = (ContentType)atoi(str);
/* Read the file size */
str = p + 1;
p = strchr(str, ',');
check_and_terminate(p);
this->curInfo->filesize = atoi(str);
/* Read the URL */
str = p + 1;
/* Is it a fallback URL? If so, just continue with the next one. */
if (strncmp(str, "ottd", 4) == 0) {
if ((uint)this->http_response_index >= this->http_response.Length()) {
/* Have we gone through all lines? */
this->OnFailure();
return;
}
continue;
}
p = strrchr(str, '/');
check(p);
char tmp[MAX_PATH];
if (strecpy(tmp, p, lastof(tmp)) == lastof(tmp)) {
this->OnFailure();
return;
}
/* Remove the extension from the string. */
for (uint i = 0; i < 2; i++) {
p = strrchr(tmp, '.');
check_and_terminate(p);
}
/* Copy the string, without extension, to the filename. */
strecpy(this->curInfo->filename, tmp, lastof(this->curInfo->filename));
/* Request the next file. */
if (!this->BeforeDownload()) {
this->OnFailure();
return;
}
NetworkHTTPSocketHandler::Connect(str, this);
return;
}
#undef check
#undef check_and_terminate
}
/**
* Create a socket handler with the given socket and (server) address.
* @param s the socket to communicate over
@ -458,6 +632,7 @@ void ClientNetworkContentSocketHandler::AfterDownload()
*/
ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() :
NetworkContentSocketHandler(),
http_response_index(-2),
curFile(NULL),
curInfo(NULL),
isConnecting(false)

View File

@ -13,6 +13,7 @@
#define NETWORK_CONTENT_H
#include "core/tcp_content.h"
#include "core/tcp_http.h"
#if defined(ENABLE_NETWORK)
@ -63,12 +64,14 @@ struct ContentCallback {
/**
* Socket handler for the content server connection
*/
class ClientNetworkContentSocketHandler : public NetworkContentSocketHandler, ContentCallback {
class ClientNetworkContentSocketHandler : public NetworkContentSocketHandler, ContentCallback, HTTPCallback {
protected:
typedef SmallVector<ContentID, 4> ContentIDList;
SmallVector<ContentCallback *, 2> callbacks; ///< Callbacks to notify "the world"
ContentIDList requested; ///< ContentIDs we already requested (so we don't do it again)
ContentVector infos; ///< All content info we received
SmallVector<char, 1024> http_response; ///< The HTTP response to the requests we've been doing
int http_response_index; ///< Where we are, in the response, with handling it
FILE *curFile; ///< Currently downloaded file
ContentInfo *curInfo; ///< Information about the currently downloaded file
@ -89,8 +92,14 @@ protected:
void OnDownloadProgress(const ContentInfo *ci, uint bytes);
void OnDownloadComplete(ContentID cid);
void OnFailure();
void OnReceiveData(const char *data, size_t length);
bool BeforeDownload();
void AfterDownload();
void DownloadSelectedContentHTTP(const ContentIDList &content);
void DownloadSelectedContentFallback(const ContentIDList &content);
public:
/** The idle timeout; when to close the connection because it's idle. */
static const int IDLE_TIMEOUT = 60 * 1000;
@ -106,7 +115,7 @@ public:
void RequestContentList(uint count, const ContentID *content_ids);
void RequestContentList(ContentVector *cv, bool send_md5sum = true);
void DownloadSelectedContent(uint &files, uint &bytes);
void DownloadSelectedContent(uint &files, uint &bytes, bool fallback = false);
void Select(ContentID cid);
void Unselect(ContentID cid);

View File

@ -147,6 +147,7 @@ struct NetworkSettings {
bool reload_cfg; ///< reload the config file before restarting
char last_host[NETWORK_HOSTNAME_LENGTH]; ///< IP address of the last joined server
uint16 last_port; ///< port of the last joined server
bool no_http_content_downloads; ///< do not do content downloads over HTTP
#else /* ENABLE_NETWORK */
#endif
};

View File

@ -631,6 +631,7 @@ const SettingDesc _settings[] = {
SDTC_BOOL(network.reload_cfg, S, NO, false, STR_NULL, NULL),
SDTC_STR(network.last_host, SLE_STRB, S, 0, "", STR_NULL, NULL),
SDTC_VAR(network.last_port, SLE_UINT16, S, 0, 0, 0, UINT16_MAX, 0, STR_NULL, NULL),
SDTC_BOOL(network.no_http_content_downloads, S, 0, false, STR_NULL, NULL),
#endif /* ENABLE_NETWORK */
/*