Merge commit '73bed054b87399484e39f6972d30f91a404daba8'
This commit is contained in:
@@ -28,6 +28,8 @@ add_files(
|
||||
network_server.h
|
||||
network_stun.cpp
|
||||
network_stun.h
|
||||
network_survey.cpp
|
||||
network_survey.h
|
||||
network_turn.cpp
|
||||
network_turn.h
|
||||
network_type.h
|
||||
|
||||
@@ -5,12 +5,11 @@ add_files(
|
||||
config.h
|
||||
core.cpp
|
||||
core.h
|
||||
em_proxy.cpp
|
||||
em_proxy.h
|
||||
game_info.cpp
|
||||
game_info.h
|
||||
network_game_info.cpp
|
||||
network_game_info.h
|
||||
host.cpp
|
||||
host.h
|
||||
http.h
|
||||
os_abstraction.cpp
|
||||
os_abstraction.h
|
||||
packet.cpp
|
||||
@@ -27,8 +26,6 @@ add_files(
|
||||
tcp_coordinator.h
|
||||
tcp_game.cpp
|
||||
tcp_game.h
|
||||
tcp_http.cpp
|
||||
tcp_http.h
|
||||
tcp_listen.h
|
||||
tcp_stun.cpp
|
||||
tcp_stun.h
|
||||
@@ -37,3 +34,16 @@ add_files(
|
||||
udp.cpp
|
||||
udp.h
|
||||
)
|
||||
|
||||
add_files(
|
||||
http_curl.cpp
|
||||
CONDITION CURL_FOUND
|
||||
)
|
||||
add_files(
|
||||
http_winhttp.cpp
|
||||
CONDITION WIN32
|
||||
)
|
||||
add_files(
|
||||
http_none.cpp
|
||||
CONDITION NOT CURL_FOUND AND NOT WIN32
|
||||
)
|
||||
|
||||
@@ -35,7 +35,7 @@ const std::string &NetworkAddress::GetHostname()
|
||||
* Get the port.
|
||||
* @return the port.
|
||||
*/
|
||||
uint16 NetworkAddress::GetPort() const
|
||||
uint16_t NetworkAddress::GetPort() const
|
||||
{
|
||||
switch (this->address.ss_family) {
|
||||
case AF_UNSPEC:
|
||||
@@ -54,7 +54,7 @@ uint16 NetworkAddress::GetPort() const
|
||||
* Set the port.
|
||||
* @param port set the port number.
|
||||
*/
|
||||
void NetworkAddress::SetPort(uint16 port)
|
||||
void NetworkAddress::SetPort(uint16_t port)
|
||||
{
|
||||
switch (this->address.ss_family) {
|
||||
case AF_UNSPEC:
|
||||
@@ -77,7 +77,7 @@ void NetworkAddress::SetPort(uint16 port)
|
||||
* @param with_family Whether to add the familty to the address (e.g. IPv4).
|
||||
* @return The format string for the address.
|
||||
*/
|
||||
static const char *GetAddressFormatString(uint16 family, bool with_family)
|
||||
static const char *GetAddressFormatString(uint16_t family, bool with_family)
|
||||
{
|
||||
switch (family) {
|
||||
case AF_INET: return with_family ? "{}:{} (IPv4)" : "{}:{}";
|
||||
@@ -93,15 +93,14 @@ static const char *GetAddressFormatString(uint16 family, bool with_family)
|
||||
*/
|
||||
std::string NetworkAddress::GetAddressAsString(bool with_family)
|
||||
{
|
||||
return fmt::format(GetAddressFormatString(this->GetAddress()->ss_family, with_family), this->GetHostname(), this->GetPort());
|
||||
return fmt::format(fmt::runtime(GetAddressFormatString(this->GetAddress()->ss_family, with_family)), this->GetHostname(), this->GetPort());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to resolve without opening a socket.
|
||||
* @param runp information about the socket to try not
|
||||
* @return the opened socket or INVALID_SOCKET
|
||||
*/
|
||||
static SOCKET ResolveLoopProc(addrinfo *runp)
|
||||
static SOCKET ResolveLoopProc(addrinfo *)
|
||||
{
|
||||
/* We just want the first 'entry', so return a valid socket. */
|
||||
return !INVALID_SOCKET;
|
||||
@@ -169,17 +168,17 @@ bool NetworkAddress::IsInNetmask(const std::string &netmask)
|
||||
|
||||
if (mask_address.GetAddressLength() == 0) return false;
|
||||
|
||||
uint32 *ip;
|
||||
uint32 *mask;
|
||||
uint32_t *ip;
|
||||
uint32_t *mask;
|
||||
switch (this->address.ss_family) {
|
||||
case AF_INET:
|
||||
ip = (uint32*)&((struct sockaddr_in*)&this->address)->sin_addr.s_addr;
|
||||
mask = (uint32*)&((struct sockaddr_in*)&mask_address.address)->sin_addr.s_addr;
|
||||
ip = (uint32_t*)&((struct sockaddr_in*)&this->address)->sin_addr.s_addr;
|
||||
mask = (uint32_t*)&((struct sockaddr_in*)&mask_address.address)->sin_addr.s_addr;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
ip = (uint32*)&((struct sockaddr_in6*)&this->address)->sin6_addr;
|
||||
mask = (uint32*)&((struct sockaddr_in6*)&mask_address.address)->sin6_addr;
|
||||
ip = (uint32_t*)&((struct sockaddr_in6*)&this->address)->sin6_addr;
|
||||
mask = (uint32_t*)&((struct sockaddr_in6*)&mask_address.address)->sin6_addr;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -187,7 +186,7 @@ bool NetworkAddress::IsInNetmask(const std::string &netmask)
|
||||
}
|
||||
|
||||
while (cidr > 0) {
|
||||
uint32 msk = cidr >= 32 ? (uint32)-1 : htonl(-(1 << (32 - cidr)));
|
||||
uint32_t msk = cidr >= 32 ? (uint32_t)-1 : htonl(-(1 << (32 - cidr)));
|
||||
if ((*mask++ & msk) != (*ip++ & msk)) return false;
|
||||
|
||||
cidr -= 32;
|
||||
@@ -215,8 +214,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
|
||||
hints.ai_socktype = socktype;
|
||||
|
||||
/* The port needs to be a string. Six is enough to contain all characters + '\0'. */
|
||||
char port_name[6];
|
||||
seprintf(port_name, lastof(port_name), "%u", this->GetPort());
|
||||
std::string port_name = std::to_string(this->GetPort());
|
||||
|
||||
bool reset_hostname = false;
|
||||
/* Setting both hostname to nullptr and port to 0 is not allowed.
|
||||
@@ -231,7 +229,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
|
||||
|
||||
static bool _resolve_timeout_error_message_shown = false;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
int e = getaddrinfo(this->hostname.empty() ? nullptr : this->hostname.c_str(), port_name, &hints, &ai);
|
||||
int e = getaddrinfo(this->hostname.empty() ? nullptr : this->hostname.c_str(), port_name.c_str(), &hints, &ai);
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
std::chrono::seconds duration = std::chrono::duration_cast<std::chrono::seconds>(end - start);
|
||||
if (!_resolve_timeout_error_message_shown && duration >= std::chrono::seconds(5)) {
|
||||
@@ -259,7 +257,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
|
||||
* of course totally unneeded ;) */
|
||||
if (sockets != nullptr) {
|
||||
NetworkAddress address(runp->ai_addr, (int)runp->ai_addrlen);
|
||||
if (sockets->Contains(address)) continue;
|
||||
if (std::any_of(sockets->begin(), sockets->end(), [&address](const auto &p) { return p.second == address; })) continue;
|
||||
}
|
||||
sock = func(runp);
|
||||
if (sock == INVALID_SOCKET) continue;
|
||||
@@ -284,7 +282,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
|
||||
}
|
||||
|
||||
NetworkAddress addr(runp->ai_addr, (int)runp->ai_addrlen);
|
||||
(*sockets)[addr] = sock;
|
||||
(*sockets)[sock] = addr;
|
||||
sock = INVALID_SOCKET;
|
||||
}
|
||||
freeaddrinfo (ai);
|
||||
@@ -317,13 +315,11 @@ static SOCKET ListenLoopProc(addrinfo *runp)
|
||||
Debug(net, 0, "Setting reuse-address mode failed: {}", NetworkError::GetLast().AsString());
|
||||
}
|
||||
|
||||
#ifndef __OS2__
|
||||
int on = 1;
|
||||
if (runp->ai_family == AF_INET6 &&
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) == -1) {
|
||||
Debug(net, 3, "Could not disable IPv4 over IPv6: {}", NetworkError::GetLast().AsString());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bind(sock, runp->ai_addr, (int)runp->ai_addrlen) != 0) {
|
||||
Debug(net, 0, "Could not bind socket on {}: {}", address, NetworkError::GetLast().AsString());
|
||||
@@ -451,14 +447,14 @@ void NetworkAddress::Listen(int socktype, SocketList *sockets)
|
||||
* @param company Pointer to the company variable to set iff indicated.
|
||||
* @return A valid ServerAddress of the parsed information.
|
||||
*/
|
||||
/* static */ ServerAddress ServerAddress::Parse(const std::string &connection_string, uint16 default_port, CompanyID *company_id)
|
||||
/* static */ ServerAddress ServerAddress::Parse(const std::string &connection_string, uint16_t default_port, CompanyID *company_id)
|
||||
{
|
||||
if (StrStartsWith(connection_string, "+")) {
|
||||
if (connection_string.starts_with("+")) {
|
||||
std::string_view invite_code = ParseCompanyFromConnectionString(connection_string, company_id);
|
||||
return ServerAddress(SERVER_ADDRESS_INVITE_CODE, std::string(invite_code));
|
||||
}
|
||||
|
||||
uint16 port = default_port;
|
||||
uint16_t port = default_port;
|
||||
std::string_view ip = ParseFullConnectionString(connection_string, port, company_id);
|
||||
return ServerAddress(SERVER_ADDRESS_DIRECT, std::string(ip) + ":" + std::to_string(port));
|
||||
}
|
||||
|
||||
@@ -14,13 +14,11 @@
|
||||
#include "config.h"
|
||||
#include "../../company_type.h"
|
||||
#include "../../string_func.h"
|
||||
#include "../../core/smallmap_type.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class NetworkAddress;
|
||||
typedef std::vector<NetworkAddress> NetworkAddressList; ///< Type for a list of addresses.
|
||||
typedef SmallMap<NetworkAddress, SOCKET> SocketList; ///< Type for a mapping between address and socket.
|
||||
using SocketList = std::map<SOCKET, NetworkAddress>; ///< Type for a mapping between address and socket.
|
||||
|
||||
/**
|
||||
* Wrapper for (un)resolved network addresses; there's no reason to transform
|
||||
@@ -74,7 +72,7 @@ public:
|
||||
* @param port the port
|
||||
* @param family the address family
|
||||
*/
|
||||
NetworkAddress(std::string_view hostname = "", uint16 port = 0, int family = AF_UNSPEC) :
|
||||
NetworkAddress(std::string_view hostname = "", uint16_t port = 0, int family = AF_UNSPEC) :
|
||||
address_length(0),
|
||||
resolved(false)
|
||||
{
|
||||
@@ -104,8 +102,8 @@ public:
|
||||
return this->address_length;
|
||||
}
|
||||
|
||||
uint16 GetPort() const;
|
||||
void SetPort(uint16 port);
|
||||
uint16_t GetPort() const;
|
||||
void SetPort(uint16_t port);
|
||||
|
||||
/**
|
||||
* Check whether the IP address has been resolved already
|
||||
@@ -211,7 +209,7 @@ public:
|
||||
ServerAddressType type; ///< The type of this ServerAddress.
|
||||
std::string connection_string; ///< The connection string for this ServerAddress.
|
||||
|
||||
static ServerAddress Parse(const std::string &connection_string, uint16 default_port, CompanyID *company_id = nullptr);
|
||||
static ServerAddress Parse(const std::string &connection_string, uint16_t default_port, CompanyID *company_id = nullptr);
|
||||
};
|
||||
|
||||
#endif /* NETWORK_CORE_ADDRESS_H */
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
#include "../../stdafx.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include "../../string_func.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
@@ -59,11 +58,21 @@ const char *NetworkContentServerConnectionString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the connection string for the content mirror from the environment variable OTTD_CONTENT_MIRROR_CS,
|
||||
* or when it has not been set a hard coded default DNS hostname of the production server.
|
||||
* @return The content mirror's connection string.
|
||||
* Get the URI string for the content mirror from the environment variable OTTD_CONTENT_MIRROR_URI,
|
||||
* or when it has not been set a hard coded URI of the production server.
|
||||
* @return The content mirror's URI string.
|
||||
*/
|
||||
const char *NetworkContentMirrorConnectionString()
|
||||
const char *NetworkContentMirrorUriString()
|
||||
{
|
||||
return GetEnv("OTTD_CONTENT_MIRROR_CS", "binaries.openttd.org");
|
||||
return GetEnv("OTTD_CONTENT_MIRROR_URI", "https://binaries.openttd.org/bananas");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URI string for the survey from the environment variable OTTD_SURVEY_URI,
|
||||
* or when it has not been set a hard coded URI of the production server.
|
||||
* @return The survey's URI string.
|
||||
*/
|
||||
const char *NetworkSurveyUriString()
|
||||
{
|
||||
return GetEnv("OTTD_SURVEY_URI", "https://survey-participate.openttd.org/");
|
||||
}
|
||||
|
||||
+18
-21
@@ -15,21 +15,19 @@
|
||||
const char *NetworkCoordinatorConnectionString();
|
||||
const char *NetworkStunConnectionString();
|
||||
const char *NetworkContentServerConnectionString();
|
||||
const char *NetworkContentMirrorConnectionString();
|
||||
const char *NetworkContentMirrorUriString();
|
||||
const char *NetworkSurveyUriString();
|
||||
|
||||
/** URL of the HTTP mirror system */
|
||||
static const char * const NETWORK_CONTENT_MIRROR_URL = "/bananas";
|
||||
static const uint16_t NETWORK_COORDINATOR_SERVER_PORT = 3976; ///< The default port of the Game Coordinator server (TCP)
|
||||
static const uint16_t NETWORK_STUN_SERVER_PORT = 3975; ///< The default port of the STUN server (TCP)
|
||||
static const uint16_t NETWORK_TURN_SERVER_PORT = 3974; ///< The default port of the TURN server (TCP)
|
||||
static const uint16_t NETWORK_CONTENT_SERVER_PORT = 3978; ///< The default port of the content server (TCP)
|
||||
static const uint16_t NETWORK_DEFAULT_PORT = 3979; ///< The default port of the game server (TCP & UDP)
|
||||
static const uint16_t NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network
|
||||
|
||||
static const uint16 NETWORK_COORDINATOR_SERVER_PORT = 3976; ///< The default port of the Game Coordinator server (TCP)
|
||||
static const uint16 NETWORK_STUN_SERVER_PORT = 3975; ///< The default port of the STUN server (TCP)
|
||||
static const uint16 NETWORK_TURN_SERVER_PORT = 3974; ///< The default port of the TURN server (TCP)
|
||||
static const uint16 NETWORK_CONTENT_SERVER_PORT = 3978; ///< The default port of the content server (TCP)
|
||||
static const uint16 NETWORK_CONTENT_MIRROR_PORT = 80; ///< The default port of the content mirror (TCP)
|
||||
static const uint16 NETWORK_DEFAULT_PORT = 3979; ///< The default port of the game server (TCP & UDP)
|
||||
static const uint16 NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network
|
||||
static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP)
|
||||
static const size_t UDP_MTU = 1460; ///< Number of bytes we can pack in a single UDP packet
|
||||
|
||||
static const uint16 UDP_MTU = 1460; ///< Number of bytes we can pack in a single UDP packet
|
||||
static const std::string NETWORK_SURVEY_DETAILS_LINK = "https://survey.openttd.org/participate"; ///< Link with more details & privacy statement of the survey.
|
||||
/*
|
||||
* Technically a TCP packet could become 64kiB, however the high bit is kept so it becomes possible in the future
|
||||
* to go to (significantly) larger packets if needed. This would entail a strategy such as employed for UTF-8.
|
||||
@@ -38,19 +36,19 @@ static const uint16 UDP_MTU = 1460; ///< Numbe
|
||||
* 00000000 00000000 0bbbbbbb aaaaaaaa -> aaaaaaaa 0bbbbbbb
|
||||
* Send_uint16(GB(size, 0, 15)
|
||||
*
|
||||
* Packets up to 1 GiB, first uint16 has high bit set so it knows to read a
|
||||
* next uint16 for the remaining bits of the size.
|
||||
* Packets up to 1 GiB, first uint16_t has high bit set so it knows to read a
|
||||
* next uint16_t for the remaining bits of the size.
|
||||
* 00dddddd cccccccc bbbbbbbb aaaaaaaa -> cccccccc 10dddddd aaaaaaaa bbbbbbbb
|
||||
* Send_uint16(GB(size, 16, 14) | 0b10 << 14)
|
||||
* Send_uint16(GB(size, 0, 16))
|
||||
*/
|
||||
static const uint16 TCP_MTU = 32767; ///< Number of bytes we can pack in a single TCP packet
|
||||
static const uint16 COMPAT_MTU = 1460; ///< Number of bytes we can pack in a single packet for backward compatibility
|
||||
static const size_t TCP_MTU = 32767; ///< Number of bytes we can pack in a single TCP packet
|
||||
static const size_t COMPAT_MTU = 1460; ///< Number of bytes we can pack in a single packet for backward compatibility
|
||||
|
||||
static const byte NETWORK_GAME_ADMIN_VERSION = 2; ///< What version of the admin network do we use?
|
||||
static const byte NETWORK_GAME_INFO_VERSION = 6; ///< What version of game-info do we use?
|
||||
static const byte NETWORK_COMPANY_INFO_VERSION = 6; ///< What version of company info is this?
|
||||
static const byte NETWORK_GAME_ADMIN_VERSION = 3; ///< What version of the admin network do we use?
|
||||
static const byte NETWORK_GAME_INFO_VERSION = 7; ///< What version of game-info do we use?
|
||||
static const byte NETWORK_COORDINATOR_VERSION = 6; ///< What version of game-coordinator-protocol do we use?
|
||||
static const byte NETWORK_SURVEY_VERSION = 1; ///< What version of the survey do we use?
|
||||
|
||||
static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0'
|
||||
static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0'
|
||||
@@ -59,10 +57,9 @@ static const uint NETWORK_HOSTNAME_PORT_LENGTH = 80 + 6; ///< The m
|
||||
static const uint NETWORK_SERVER_ID_LENGTH = 33; ///< The maximum length of the network id of the servers, in bytes including '\0'
|
||||
static const uint NETWORK_REVISION_LENGTH = 33; ///< The maximum length of the revision, in bytes including '\0'
|
||||
static const uint NETWORK_PASSWORD_LENGTH = 33; ///< The maximum length of the password, in bytes including '\0' (must be >= NETWORK_SERVER_ID_LENGTH)
|
||||
static const uint NETWORK_CLIENTS_LENGTH = 200; ///< The maximum length for the list of clients that controls a company, in bytes including '\0'
|
||||
static const uint NETWORK_CLIENT_NAME_LENGTH = 25; ///< The maximum length of a client's name, in bytes including '\0'
|
||||
static const uint NETWORK_RCONCOMMAND_LENGTH = 500; ///< The maximum length of a rconsole command, in bytes including '\0'
|
||||
static const uint NETWORK_GAMESCRIPT_JSON_LENGTH = COMPAT_MTU - 3; ///< The maximum length of a gamescript json string, in bytes including '\0'. Must not be longer than COMPAT_MTU including header (3 bytes)
|
||||
static const uint NETWORK_GAMESCRIPT_JSON_LENGTH = 9000; ///< The maximum length of a receiving gamescript json string, in bytes including '\0'.
|
||||
static const uint NETWORK_CHAT_LENGTH = 900; ///< The maximum length of a chat message, in bytes including '\0'
|
||||
static const uint NETWORK_CONTENT_FILENAME_LENGTH = 48; ///< The maximum length of a content's filename, in bytes including '\0'.
|
||||
static const uint NETWORK_CONTENT_NAME_LENGTH = 32; ///< The maximum length of a content's name, in bytes including '\0'.
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
NetworkSocketHandler() { this->has_quit = false; }
|
||||
|
||||
/** Close the socket when destructing the socket handler */
|
||||
virtual ~NetworkSocketHandler() {}
|
||||
virtual ~NetworkSocketHandler() = default;
|
||||
|
||||
/**
|
||||
* Mark the connection as closed.
|
||||
|
||||
+15
-58
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../core/alloc_func.hpp"
|
||||
#include "address.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
@@ -20,25 +21,7 @@
|
||||
*/
|
||||
static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast);
|
||||
|
||||
#if defined(HAVE_GETIFADDRS)
|
||||
static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // GETIFADDRS implementation
|
||||
{
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
|
||||
if (getifaddrs(&ifap) != 0) return;
|
||||
|
||||
for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||
if (!(ifa->ifa_flags & IFF_BROADCAST)) continue;
|
||||
if (ifa->ifa_broadaddr == nullptr) continue;
|
||||
if (ifa->ifa_broadaddr->sa_family != AF_INET) continue;
|
||||
|
||||
NetworkAddress addr(ifa->ifa_broadaddr, sizeof(sockaddr));
|
||||
if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const& elem) -> bool { return elem == addr; })) broadcast->push_back(addr);
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
#ifdef _WIN32
|
||||
static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // Win32 implementation
|
||||
{
|
||||
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
@@ -69,55 +52,29 @@ static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // Wi
|
||||
memcpy(&address, &ifo[j].iiAddress.Address, sizeof(sockaddr));
|
||||
((sockaddr_in*)&address)->sin_addr.s_addr = ifo[j].iiAddress.AddressIn.sin_addr.s_addr | ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr;
|
||||
NetworkAddress addr(address, sizeof(sockaddr));
|
||||
if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const& elem) -> bool { return elem == addr; })) broadcast->push_back(addr);
|
||||
if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const &elem) -> bool { return elem == addr; })) broadcast->push_back(addr);
|
||||
}
|
||||
|
||||
free(ifo);
|
||||
closesocket(sock);
|
||||
}
|
||||
|
||||
#else /* not HAVE_GETIFADDRS */
|
||||
|
||||
#include "../../string_func.h"
|
||||
|
||||
static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // !GETIFADDRS implementation
|
||||
#else /* not WIN32 */
|
||||
static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast)
|
||||
{
|
||||
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == INVALID_SOCKET) return;
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
|
||||
char buf[4 * 1024]; // Arbitrary buffer size
|
||||
struct ifconf ifconf;
|
||||
if (getifaddrs(&ifap) != 0) return;
|
||||
|
||||
ifconf.ifc_len = sizeof(buf);
|
||||
ifconf.ifc_buf = buf;
|
||||
if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) {
|
||||
closesocket(sock);
|
||||
return;
|
||||
for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||
if (!(ifa->ifa_flags & IFF_BROADCAST)) continue;
|
||||
if (ifa->ifa_broadaddr == nullptr) continue;
|
||||
if (ifa->ifa_broadaddr->sa_family != AF_INET) continue;
|
||||
|
||||
NetworkAddress addr(ifa->ifa_broadaddr, sizeof(sockaddr));
|
||||
if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const &elem) -> bool { return elem == addr; })) broadcast->push_back(addr);
|
||||
}
|
||||
|
||||
const char *buf_end = buf + ifconf.ifc_len;
|
||||
for (const char *p = buf; p < buf_end;) {
|
||||
const struct ifreq *req = (const struct ifreq*)p;
|
||||
|
||||
if (req->ifr_addr.sa_family == AF_INET) {
|
||||
struct ifreq r;
|
||||
|
||||
strecpy(r.ifr_name, req->ifr_name, lastof(r.ifr_name));
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 &&
|
||||
(r.ifr_flags & IFF_BROADCAST) &&
|
||||
ioctl(sock, SIOCGIFBRDADDR, &r) != -1) {
|
||||
NetworkAddress addr(&r.ifr_broadaddr, sizeof(sockaddr));
|
||||
if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const& elem) -> bool { return elem == addr; })) broadcast->push_back(addr);
|
||||
}
|
||||
}
|
||||
|
||||
p += sizeof(struct ifreq);
|
||||
#if defined(AF_LINK) && !defined(SUNOS)
|
||||
p += req->ifr_addr.sa_len - sizeof(struct sockaddr);
|
||||
#endif
|
||||
}
|
||||
|
||||
closesocket(sock);
|
||||
freeifaddrs(ifap);
|
||||
}
|
||||
#endif /* all NetworkFindBroadcastIPsInternals */
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 http.h Basic functions to send and receive HTTP packets.
|
||||
*/
|
||||
|
||||
#ifndef NETWORK_CORE_HTTP_H
|
||||
#define NETWORK_CORE_HTTP_H
|
||||
|
||||
#include "tcp.h"
|
||||
|
||||
constexpr int HTTP_429_TOO_MANY_REQUESTS = 429;
|
||||
|
||||
/** Callback for when the HTTP handler has something to tell us. */
|
||||
struct HTTPCallback {
|
||||
/**
|
||||
* An error has occurred 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, nullptr when all data has been received.
|
||||
* @param length the amount of received data, 0 when all data has been received.
|
||||
* @note When nullptr is sent the HTTP socket handler is closed/freed.
|
||||
*/
|
||||
virtual void OnReceiveData(std::unique_ptr<char[]> data, size_t length) = 0;
|
||||
|
||||
/**
|
||||
* Check if there is a request to cancel the transfer.
|
||||
*
|
||||
* @return true iff the connection is cancelled.
|
||||
* @note Cancellations are never instant, and can take a bit of time to be processed.
|
||||
* The object needs to remain valid until the OnFailure() callback is called.
|
||||
*/
|
||||
virtual bool IsCancelled() const = 0;
|
||||
|
||||
/** Silentium */
|
||||
virtual ~HTTPCallback() = default;
|
||||
};
|
||||
|
||||
/** Base socket handler for HTTP traffic. */
|
||||
class NetworkHTTPSocketHandler {
|
||||
public:
|
||||
/**
|
||||
* Connect to the given URI.
|
||||
*
|
||||
* @param uri the URI to connect to (https://.../..).
|
||||
* @param callback the callback to send data back on.
|
||||
* @param data the data we want to send. When non-empty, this will be a POST request, otherwise a GET request.
|
||||
*/
|
||||
static void Connect(const std::string &uri, HTTPCallback *callback, const std::string data = "");
|
||||
|
||||
/**
|
||||
* Do the receiving for all HTTP connections.
|
||||
*/
|
||||
static void HTTPReceive();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the HTTP socket handler.
|
||||
*/
|
||||
void NetworkHTTPInitialize();
|
||||
|
||||
/**
|
||||
* Uninitialize the HTTP socket handler.
|
||||
*/
|
||||
void NetworkHTTPUninitialize();
|
||||
|
||||
#endif /* NETWORK_CORE_HTTP_H */
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* 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 http_curl.cpp CURL-based implementation for HTTP requests.
|
||||
*/
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../fileio_func.h"
|
||||
#include "../../rev.h"
|
||||
#include "../../thread.h"
|
||||
#include "../network_internal.h"
|
||||
|
||||
#include "http.h"
|
||||
#include "http_shared.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <curl/curl.h>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
#if defined(UNIX)
|
||||
/** List of certificate bundles, depending on OS. Taken from: https://go.dev/src/crypto/x509/root_linux.go. */
|
||||
static auto _certificate_files = {
|
||||
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
|
||||
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
|
||||
"/etc/ssl/ca-bundle.pem", // OpenSUSE
|
||||
"/etc/pki/tls/cacert.pem", // OpenELEC
|
||||
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
|
||||
"/etc/ssl/cert.pem", // Alpine Linux
|
||||
};
|
||||
/** List of certificate directories, depending on OS. Taken from: https://go.dev/src/crypto/x509/root_linux.go. */
|
||||
static auto _certificate_directories = {
|
||||
"/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139
|
||||
"/etc/pki/tls/certs", // Fedora/RHEL
|
||||
"/system/etc/security/cacerts", // Android
|
||||
};
|
||||
#endif /* UNIX */
|
||||
|
||||
static std::vector<HTTPThreadSafeCallback *> _http_callbacks;
|
||||
static std::vector<HTTPThreadSafeCallback *> _new_http_callbacks;
|
||||
static std::mutex _http_callback_mutex;
|
||||
static std::mutex _new_http_callback_mutex;
|
||||
|
||||
/** Single HTTP request. */
|
||||
class NetworkHTTPRequest {
|
||||
public:
|
||||
/**
|
||||
* Create a new HTTP request.
|
||||
*
|
||||
* @param uri the URI to connect to (https://.../..).
|
||||
* @param callback the callback to send data back on.
|
||||
* @param data the data we want to send. When non-empty, this will be a POST request, otherwise a GET request.
|
||||
*/
|
||||
NetworkHTTPRequest(const std::string &uri, HTTPCallback *callback, const std::string &data) :
|
||||
uri(uri),
|
||||
callback(callback),
|
||||
data(data)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_new_http_callback_mutex);
|
||||
_new_http_callbacks.push_back(&this->callback);
|
||||
}
|
||||
|
||||
~NetworkHTTPRequest()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_http_callback_mutex);
|
||||
_http_callbacks.erase(std::remove(_http_callbacks.begin(), _http_callbacks.end(), &this->callback), _http_callbacks.end());
|
||||
}
|
||||
|
||||
const std::string uri; ///< URI to connect to.
|
||||
HTTPThreadSafeCallback callback; ///< Callback to send data back on.
|
||||
const std::string data; ///< Data to send, if any.
|
||||
};
|
||||
|
||||
static std::thread _http_thread;
|
||||
static std::atomic<bool> _http_thread_exit = false;
|
||||
static std::queue<std::unique_ptr<NetworkHTTPRequest>> _http_requests;
|
||||
static std::mutex _http_mutex;
|
||||
static std::condition_variable _http_cv;
|
||||
#if defined(UNIX)
|
||||
static std::string _http_ca_file = "";
|
||||
static std::string _http_ca_path = "";
|
||||
#endif /* UNIX */
|
||||
|
||||
/* static */ void NetworkHTTPSocketHandler::Connect(const std::string &uri, HTTPCallback *callback, const std::string data)
|
||||
{
|
||||
#if defined(UNIX)
|
||||
if (_http_ca_file.empty() && _http_ca_path.empty()) {
|
||||
callback->OnFailure();
|
||||
return;
|
||||
}
|
||||
#endif /* UNIX */
|
||||
|
||||
std::lock_guard<std::mutex> lock(_http_mutex);
|
||||
_http_requests.push(std::make_unique<NetworkHTTPRequest>(uri, callback, data));
|
||||
_http_cv.notify_one();
|
||||
}
|
||||
|
||||
/* static */ void NetworkHTTPSocketHandler::HTTPReceive()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_http_callback_mutex);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_new(_new_http_callback_mutex);
|
||||
if (!_new_http_callbacks.empty()) {
|
||||
/* We delay adding new callbacks, as HandleQueue() below might add a new callback. */
|
||||
_http_callbacks.insert(_http_callbacks.end(), _new_http_callbacks.begin(), _new_http_callbacks.end());
|
||||
_new_http_callbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &callback : _http_callbacks) {
|
||||
callback->HandleQueue();
|
||||
}
|
||||
}
|
||||
|
||||
void HttpThread()
|
||||
{
|
||||
CURL *curl = curl_easy_init();
|
||||
assert(curl != nullptr);
|
||||
|
||||
for (;;) {
|
||||
std::unique_lock<std::mutex> lock(_http_mutex);
|
||||
|
||||
/* Wait for a new request. */
|
||||
while (_http_requests.empty() && !_http_thread_exit) {
|
||||
_http_cv.wait(lock);
|
||||
}
|
||||
if (_http_thread_exit) break;
|
||||
|
||||
std::unique_ptr<NetworkHTTPRequest> request = std::move(_http_requests.front());
|
||||
_http_requests.pop();
|
||||
|
||||
/* Release the lock, as we will take a while to process the request. */
|
||||
lock.unlock();
|
||||
|
||||
/* Reset to default settings. */
|
||||
curl_easy_reset(curl);
|
||||
curl_slist *headers = nullptr;
|
||||
|
||||
if (_debug_net_level >= 5) {
|
||||
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||
}
|
||||
|
||||
/* Setup some default options. */
|
||||
std::string user_agent = fmt::format("OpenTTD/{}", GetNetworkRevisionString());
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L);
|
||||
|
||||
/* Ensure we validate the certificate and hostname of the server. */
|
||||
#if defined(UNIX)
|
||||
curl_easy_setopt(curl, CURLOPT_CAINFO, _http_ca_file.empty() ? nullptr : _http_ca_file.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_CAPATH, _http_ca_path.empty() ? nullptr : _http_ca_path.c_str());
|
||||
#endif /* UNIX */
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
|
||||
|
||||
/* Give the connection about 10 seconds to complete. */
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);
|
||||
|
||||
/* Set a buffer of 100KiB, as the default of 16KiB seems a bit small. */
|
||||
curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 100L * 1024L);
|
||||
|
||||
/* Fail our call if we don't receive a 2XX return value. */
|
||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
|
||||
|
||||
/* Prepare POST body and URI. */
|
||||
if (!request->data.empty()) {
|
||||
/* When the payload starts with a '{', it is a JSON payload. */
|
||||
if (request->data.starts_with("{")) {
|
||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||
} else {
|
||||
headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request->data.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
}
|
||||
curl_easy_setopt(curl, CURLOPT_URL, request->uri.c_str());
|
||||
|
||||
/* Setup our (C-style) callback function which we pipe back into the callback. */
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, +[](char *ptr, size_t size, size_t nmemb, void *userdata) -> size_t {
|
||||
Debug(net, 6, "HTTP callback: {} bytes", size * nmemb);
|
||||
HTTPThreadSafeCallback *callback = static_cast<HTTPThreadSafeCallback *>(userdata);
|
||||
|
||||
/* Copy the buffer out of CURL. OnReceiveData() will free it when done. */
|
||||
std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size * nmemb);
|
||||
memcpy(buffer.get(), ptr, size * nmemb);
|
||||
callback->OnReceiveData(std::move(buffer), size * nmemb);
|
||||
|
||||
return size * nmemb;
|
||||
});
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &request->callback);
|
||||
|
||||
/* Create a callback from which we can cancel. Sadly, there is no other
|
||||
* thread-safe way to do this. If the connection went idle, it can take
|
||||
* up to a second before this callback is called. There is little we can
|
||||
* do about this. */
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, +[](void *userdata, curl_off_t /*dltotal*/, curl_off_t /*dlnow*/, curl_off_t /*ultotal*/, curl_off_t /*ulnow*/) -> int {
|
||||
const HTTPThreadSafeCallback *callback = static_cast<HTTPThreadSafeCallback *>(userdata);
|
||||
return (callback->cancelled || _http_thread_exit) ? 1 : 0;
|
||||
});
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &request->callback);
|
||||
|
||||
/* Perform the request. */
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
|
||||
curl_slist_free_all(headers);
|
||||
|
||||
if (res == CURLE_OK) {
|
||||
Debug(net, 1, "HTTP request succeeded");
|
||||
request->callback.OnReceiveData(nullptr, 0);
|
||||
} else {
|
||||
long status_code = 0;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status_code);
|
||||
|
||||
/* No need to be verbose about rate limiting. */
|
||||
Debug(net, (request->callback.cancelled || _http_thread_exit || status_code == HTTP_429_TOO_MANY_REQUESTS) ? 1 : 0, "HTTP request failed: status_code: {}, error: {}", status_code, curl_easy_strerror(res));
|
||||
request->callback.OnFailure();
|
||||
}
|
||||
|
||||
/* Wait till the callback tells us all data is dequeued, or _http_thread_exit has been set. */
|
||||
request->callback.WaitTillEmptyOrCondition([]() -> bool {
|
||||
return _http_thread_exit;
|
||||
});
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
void NetworkHTTPInitialize()
|
||||
{
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
|
||||
#if defined(UNIX)
|
||||
/* Depending on the Linux distro, certificates can either be in
|
||||
* a bundle or a folder, in a wide range of different locations.
|
||||
* Try to find what location is used by this OS. */
|
||||
for (auto &ca_file : _certificate_files) {
|
||||
if (FileExists(ca_file)) {
|
||||
_http_ca_file = ca_file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_http_ca_file.empty()) {
|
||||
for (auto &ca_path : _certificate_directories) {
|
||||
if (FileExists(ca_path)) {
|
||||
_http_ca_path = ca_path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Debug(net, 3, "Using certificate file: {}", _http_ca_file.empty() ? "none" : _http_ca_file);
|
||||
Debug(net, 3, "Using certificate path: {}", _http_ca_path.empty() ? "none" : _http_ca_path);
|
||||
|
||||
/* Tell the user why HTTPS will not be working. */
|
||||
if (_http_ca_file.empty() && _http_ca_path.empty()) {
|
||||
Debug(net, 0, "No certificate files or directories found, HTTPS will not work!");
|
||||
}
|
||||
#endif /* UNIX */
|
||||
|
||||
_http_thread_exit = false;
|
||||
StartNewThread(&_http_thread, "ottd:http", &HttpThread);
|
||||
}
|
||||
|
||||
void NetworkHTTPUninitialize()
|
||||
{
|
||||
_http_thread_exit = true;
|
||||
|
||||
/* Ensure the callbacks are handled. This is mostly needed as we send
|
||||
* a survey just before close, and that might be pending here. */
|
||||
NetworkHTTPSocketHandler::HTTPReceive();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_http_mutex);
|
||||
_http_cv.notify_one();
|
||||
}
|
||||
|
||||
if (_http_thread.joinable()) {
|
||||
_http_thread.join();
|
||||
}
|
||||
|
||||
curl_global_cleanup();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 http_emscripten.cpp Emscripten-based implementation for HTTP requests.
|
||||
*/
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../rev.h"
|
||||
#include "../network_internal.h"
|
||||
|
||||
#include "http.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/* static */ void NetworkHTTPSocketHandler::Connect(const std::string &, HTTPCallback *callback, const std::string)
|
||||
{
|
||||
/* No valid HTTP backend was compiled in, so we fail all HTTP requests. */
|
||||
callback->OnFailure();
|
||||
}
|
||||
|
||||
/* static */ void NetworkHTTPSocketHandler::HTTPReceive()
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkHTTPInitialize()
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkHTTPUninitialize()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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 http_shared.h Shared functions for implementations of HTTP requests.
|
||||
*/
|
||||
|
||||
#ifndef NETWORK_CORE_HTTP_SHARED_H
|
||||
#define NETWORK_CORE_HTTP_SHARED_H
|
||||
|
||||
#include "http.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
/** Converts a HTTPCallback to a Thread-Safe variant. */
|
||||
class HTTPThreadSafeCallback {
|
||||
private:
|
||||
/** Entries on the queue for later handling. */
|
||||
class Callback {
|
||||
public:
|
||||
Callback(std::unique_ptr<char[]> data, size_t length) : data(std::move(data)), length(length), failure(false) {}
|
||||
Callback() : data(nullptr), length(0), failure(true) {}
|
||||
|
||||
std::unique_ptr<char[]> data;
|
||||
size_t length;
|
||||
bool failure;
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* Similar to HTTPCallback::OnFailure, but thread-safe.
|
||||
*/
|
||||
void OnFailure()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
this->queue.emplace_back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to HTTPCallback::OnReceiveData, but thread-safe.
|
||||
*/
|
||||
void OnReceiveData(std::unique_ptr<char[]> data, size_t length)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
this->queue.emplace_back(std::move(data), length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process everything on the queue.
|
||||
*
|
||||
* Should be called from the Game Thread.
|
||||
*/
|
||||
void HandleQueue()
|
||||
{
|
||||
this->cancelled = callback->IsCancelled();
|
||||
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
for (auto &item : this->queue) {
|
||||
if (item.failure) {
|
||||
this->callback->OnFailure();
|
||||
} else {
|
||||
this->callback->OnReceiveData(std::move(item.data), item.length);
|
||||
}
|
||||
}
|
||||
|
||||
this->queue.clear();
|
||||
this->queue_cv.notify_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait till the queue is dequeued, or a condition is met.
|
||||
* @param condition Condition functor.
|
||||
*/
|
||||
template <typename T>
|
||||
void WaitTillEmptyOrCondition(T condition)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
|
||||
while (!(queue.empty() || condition())) {
|
||||
this->queue_cv.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the queue is empty.
|
||||
*/
|
||||
bool IsQueueEmpty()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
return this->queue.empty();
|
||||
}
|
||||
|
||||
HTTPThreadSafeCallback(HTTPCallback *callback) : callback(callback) {}
|
||||
|
||||
~HTTPThreadSafeCallback()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
/* Clear the list and notify explicitly. */
|
||||
queue.clear();
|
||||
queue_cv.notify_all();
|
||||
}
|
||||
|
||||
std::atomic<bool> cancelled = false;
|
||||
|
||||
private:
|
||||
HTTPCallback *callback; ///< The callback to send data back on.
|
||||
std::mutex mutex; ///< Mutex to protect the queue.
|
||||
std::vector<Callback> queue; ///< Queue of data to send back.
|
||||
std::condition_variable queue_cv; ///< Condition variable to wait for the queue to be empty.
|
||||
};
|
||||
|
||||
#endif /* NETWORK_CORE_HTTP_SHARED_H */
|
||||
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* 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 http_winhttp.cpp WinHTTP-based implementation for HTTP requests.
|
||||
*/
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../rev.h"
|
||||
#include "../network_internal.h"
|
||||
|
||||
#include "http.h"
|
||||
#include "http_shared.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <winhttp.h>
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
static HINTERNET _winhttp_session = nullptr;
|
||||
|
||||
/** Single HTTP request. */
|
||||
class NetworkHTTPRequest {
|
||||
private:
|
||||
const std::wstring uri; ///< URI to connect to.
|
||||
HTTPThreadSafeCallback callback; ///< Callback to send data back on.
|
||||
const std::string data; ///< Data to send, if any.
|
||||
|
||||
HINTERNET connection = nullptr; ///< Current connection object.
|
||||
HINTERNET request = nullptr; ///< Current request object.
|
||||
std::atomic<bool> finished = false; ///< Whether we are finished with the request.
|
||||
int depth = 0; ///< Current redirect depth we are in.
|
||||
|
||||
public:
|
||||
NetworkHTTPRequest(const std::wstring &uri, HTTPCallback *callback, const std::string &data);
|
||||
|
||||
~NetworkHTTPRequest();
|
||||
|
||||
void Connect();
|
||||
bool Receive();
|
||||
void WinHttpCallback(DWORD code, void *info, DWORD length);
|
||||
};
|
||||
|
||||
static std::vector<NetworkHTTPRequest *> _http_requests;
|
||||
static std::vector<NetworkHTTPRequest *> _new_http_requests;
|
||||
static std::mutex _new_http_requests_mutex;
|
||||
|
||||
static std::vector<HTTPThreadSafeCallback *> _http_callbacks;
|
||||
static std::vector<HTTPThreadSafeCallback *> _new_http_callbacks;
|
||||
static std::mutex _http_callback_mutex;
|
||||
static std::mutex _new_http_callback_mutex;
|
||||
|
||||
/**
|
||||
* Create a new HTTP request.
|
||||
*
|
||||
* @param uri the URI to connect to (https://.../..).
|
||||
* @param callback the callback to send data back on.
|
||||
* @param data the data we want to send. When non-empty, this will be a POST request, otherwise a GET request.
|
||||
*/
|
||||
NetworkHTTPRequest::NetworkHTTPRequest(const std::wstring &uri, HTTPCallback *callback, const std::string &data) :
|
||||
uri(uri),
|
||||
callback(callback),
|
||||
data(data)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_new_http_callback_mutex);
|
||||
_new_http_callbacks.push_back(&this->callback);
|
||||
}
|
||||
|
||||
static std::string GetLastErrorAsString()
|
||||
{
|
||||
wchar_t buffer[512];
|
||||
|
||||
DWORD error_code = GetLastError();
|
||||
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, GetModuleHandle(L"winhttp.dll"), error_code,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, lengthof(buffer), nullptr) == 0) {
|
||||
return fmt::format("unknown error {}", error_code);
|
||||
}
|
||||
|
||||
return FS2OTTD(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback from the WinHTTP library, called when-ever something changes about the HTTP request status.
|
||||
*
|
||||
* The callback needs to call some WinHttp functions for certain states, so WinHttp continues
|
||||
* to read the request. This also allows us to abort when things go wrong, by simply not calling
|
||||
* those functions.
|
||||
* Comments with "Next step:" mark where WinHttp needs a call to continue.
|
||||
*
|
||||
* @param code The code of the event.
|
||||
* @param info The information about the event.
|
||||
* @param length The length of the information.
|
||||
*/
|
||||
void NetworkHTTPRequest::WinHttpCallback(DWORD code, void *info, DWORD length)
|
||||
{
|
||||
if (this->finished) return;
|
||||
|
||||
switch (code) {
|
||||
case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME:
|
||||
case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED:
|
||||
case WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER:
|
||||
case WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER:
|
||||
case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
|
||||
case WINHTTP_CALLBACK_STATUS_REQUEST_SENT:
|
||||
case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE:
|
||||
case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED:
|
||||
case WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION:
|
||||
case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED:
|
||||
case WINHTTP_CALLBACK_STATUS_HANDLE_CREATED:
|
||||
case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
|
||||
/* We don't care about these events, and explicitly ignore them. */
|
||||
break;
|
||||
|
||||
case WINHTTP_CALLBACK_STATUS_REDIRECT:
|
||||
/* Make sure we are not in a redirect loop. */
|
||||
if (this->depth++ > 5) {
|
||||
Debug(net, 0, "HTTP request failed: too many redirects");
|
||||
this->finished = true;
|
||||
this->callback.OnFailure();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
|
||||
/* Next step: read response. */
|
||||
WinHttpReceiveResponse(this->request, nullptr);
|
||||
break;
|
||||
|
||||
case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
|
||||
{
|
||||
/* Retrieve the status code. */
|
||||
DWORD status_code = 0;
|
||||
DWORD status_code_size = sizeof(status_code);
|
||||
WinHttpQueryHeaders(this->request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status_code, &status_code_size, WINHTTP_NO_HEADER_INDEX);
|
||||
Debug(net, 3, "HTTP request status code: {}", status_code);
|
||||
|
||||
/* If there is any error, we simply abort the request. */
|
||||
if (status_code >= 400) {
|
||||
/* No need to be verbose about rate limiting. */
|
||||
Debug(net, status_code == HTTP_429_TOO_MANY_REQUESTS ? 1 : 0, "HTTP request failed: status-code {}", status_code);
|
||||
this->finished = true;
|
||||
this->callback.OnFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Next step: query for any data. */
|
||||
WinHttpQueryDataAvailable(this->request, nullptr);
|
||||
} break;
|
||||
|
||||
case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
|
||||
{
|
||||
/* Retrieve the amount of data available to process. */
|
||||
DWORD size = *(DWORD *)info;
|
||||
|
||||
/* Next step: read the data in a temporary allocated buffer.
|
||||
* The buffer will be free'd by OnReceiveData() in the next step. */
|
||||
char *buffer = size == 0 ? nullptr : new char[size];
|
||||
WinHttpReadData(this->request, buffer, size, 0);
|
||||
} break;
|
||||
|
||||
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
|
||||
Debug(net, 6, "HTTP callback: {} bytes", length);
|
||||
|
||||
this->callback.OnReceiveData(std::unique_ptr<char[]>(static_cast<char *>(info)), length);
|
||||
|
||||
if (length == 0) {
|
||||
/* Next step: no more data available: request is finished. */
|
||||
this->finished = true;
|
||||
Debug(net, 1, "HTTP request succeeded");
|
||||
} else {
|
||||
/* Next step: query for more data. */
|
||||
WinHttpQueryDataAvailable(this->request, nullptr);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
|
||||
case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
|
||||
Debug(net, 0, "HTTP request failed: {}", GetLastErrorAsString());
|
||||
this->finished = true;
|
||||
this->callback.OnFailure();
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug(net, 0, "HTTP request failed: unexepected callback code 0x{:x}", code);
|
||||
this->finished = true;
|
||||
this->callback.OnFailure();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void CALLBACK StaticWinHttpCallback(HINTERNET, DWORD_PTR context, DWORD code, void *info, DWORD length)
|
||||
{
|
||||
if (context == 0) return;
|
||||
|
||||
NetworkHTTPRequest *request = (NetworkHTTPRequest *)context;
|
||||
request->WinHttpCallback(code, info, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the HTTP request handling.
|
||||
*
|
||||
* This is done in an async manner, so we can do other things while waiting for
|
||||
* the HTTP request to finish. The actual receiving of the data is done in
|
||||
* Receive().
|
||||
*/
|
||||
void NetworkHTTPRequest::Connect()
|
||||
{
|
||||
Debug(net, 1, "HTTP request to {}", std::string(uri.begin(), uri.end()));
|
||||
|
||||
URL_COMPONENTS url_components = {};
|
||||
wchar_t scheme[32];
|
||||
wchar_t hostname[128];
|
||||
wchar_t url_path[4096];
|
||||
|
||||
/* Convert the URL to its components. */
|
||||
url_components.dwStructSize = sizeof(url_components);
|
||||
url_components.lpszScheme = scheme;
|
||||
url_components.dwSchemeLength = lengthof(scheme);
|
||||
url_components.lpszHostName = hostname;
|
||||
url_components.dwHostNameLength = lengthof(hostname);
|
||||
url_components.lpszUrlPath = url_path;
|
||||
url_components.dwUrlPathLength = lengthof(url_path);
|
||||
WinHttpCrackUrl(this->uri.c_str(), 0, 0, &url_components);
|
||||
|
||||
/* Create the HTTP connection. */
|
||||
this->connection = WinHttpConnect(_winhttp_session, url_components.lpszHostName, url_components.nPort, 0);
|
||||
if (this->connection == nullptr) {
|
||||
Debug(net, 0, "HTTP request failed: {}", GetLastErrorAsString());
|
||||
this->finished = true;
|
||||
this->callback.OnFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
this->request = WinHttpOpenRequest(connection, data.empty() ? L"GET" : L"POST", url_components.lpszUrlPath, nullptr, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, url_components.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0);
|
||||
if (this->request == nullptr) {
|
||||
WinHttpCloseHandle(this->connection);
|
||||
|
||||
Debug(net, 0, "HTTP request failed: {}", GetLastErrorAsString());
|
||||
this->finished = true;
|
||||
this->callback.OnFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send the request (possibly with a payload). */
|
||||
if (data.empty()) {
|
||||
WinHttpSendRequest(this->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, reinterpret_cast<DWORD_PTR>(this));
|
||||
} else {
|
||||
/* When the payload starts with a '{', it is a JSON payload. */
|
||||
LPCWSTR content_type = data.starts_with("{") ? L"Content-Type: application/json\r\n" : L"Content-Type: application/x-www-form-urlencoded\r\n";
|
||||
WinHttpSendRequest(this->request, content_type, -1, const_cast<char *>(data.c_str()), static_cast<DWORD>(data.size()), static_cast<DWORD>(data.size()), reinterpret_cast<DWORD_PTR>(this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll and process the HTTP request/response.
|
||||
*
|
||||
* @return True iff the request is done; no call to Receive() should be done after it returns true.
|
||||
*/
|
||||
bool NetworkHTTPRequest::Receive()
|
||||
{
|
||||
if (this->callback.cancelled && !this->finished) {
|
||||
Debug(net, 1, "HTTP request failed: cancelled by user");
|
||||
this->finished = true;
|
||||
this->callback.OnFailure();
|
||||
/* Fall-through, as we are waiting for IsQueueEmpty() to happen. */
|
||||
}
|
||||
|
||||
return this->finished && this->callback.IsQueueEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor of the HTTP request.
|
||||
*
|
||||
* Makes sure all handlers are closed, and all memory is free'd.
|
||||
*/
|
||||
NetworkHTTPRequest::~NetworkHTTPRequest()
|
||||
{
|
||||
if (this->request) {
|
||||
WinHttpCloseHandle(this->request);
|
||||
WinHttpCloseHandle(this->connection);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(_http_callback_mutex);
|
||||
_http_callbacks.erase(std::remove(_http_callbacks.begin(), _http_callbacks.end(), &this->callback), _http_callbacks.end());
|
||||
}
|
||||
|
||||
/* static */ void NetworkHTTPSocketHandler::Connect(const std::string &uri, HTTPCallback *callback, const std::string data)
|
||||
{
|
||||
auto request = new NetworkHTTPRequest(std::wstring(uri.begin(), uri.end()), callback, data);
|
||||
request->Connect();
|
||||
|
||||
std::lock_guard<std::mutex> lock(_new_http_requests_mutex);
|
||||
_new_http_requests.push_back(request);
|
||||
}
|
||||
|
||||
/* static */ void NetworkHTTPSocketHandler::HTTPReceive()
|
||||
{
|
||||
/* Process all callbacks. */
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_http_callback_mutex);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_new_http_callback_mutex);
|
||||
if (!_new_http_callbacks.empty()) {
|
||||
/* We delay adding new callbacks, as HandleQueue() below might add a new callback. */
|
||||
_http_callbacks.insert(_http_callbacks.end(), _new_http_callbacks.begin(), _new_http_callbacks.end());
|
||||
_new_http_callbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &callback : _http_callbacks) {
|
||||
callback->HandleQueue();
|
||||
}
|
||||
}
|
||||
|
||||
/* Process all requests. */
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_new_http_requests_mutex);
|
||||
if (!_new_http_requests.empty()) {
|
||||
/* We delay adding new requests, as Receive() below can cause a callback which adds a new requests. */
|
||||
_http_requests.insert(_http_requests.end(), _new_http_requests.begin(), _new_http_requests.end());
|
||||
_new_http_requests.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (_http_requests.empty()) return;
|
||||
|
||||
for (auto it = _http_requests.begin(); it != _http_requests.end(); /* nothing */) {
|
||||
NetworkHTTPRequest *cur = *it;
|
||||
|
||||
if (cur->Receive()) {
|
||||
it = _http_requests.erase(it);
|
||||
delete cur;
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkHTTPInitialize()
|
||||
{
|
||||
/* We create a single session, from which we build up every other request. */
|
||||
std::string user_agent = fmt::format("OpenTTD/{}", GetNetworkRevisionString());
|
||||
_winhttp_session = WinHttpOpen(std::wstring(user_agent.begin(), user_agent.end()).c_str(), WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC);
|
||||
|
||||
/* Set the callback function for all requests. The "context" maps it back into the actual request instance. */
|
||||
WinHttpSetStatusCallback(_winhttp_session, StaticWinHttpCallback, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0);
|
||||
|
||||
/* 10 seconds timeout for requests. */
|
||||
WinHttpSetTimeouts(_winhttp_session, 10000, 10000, 10000, 10000);
|
||||
}
|
||||
|
||||
void NetworkHTTPUninitialize()
|
||||
{
|
||||
WinHttpCloseHandle(_winhttp_session);
|
||||
}
|
||||
@@ -10,10 +10,11 @@
|
||||
*/
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "game_info.h"
|
||||
#include "network_game_info.h"
|
||||
#include "../../core/bitmath_func.hpp"
|
||||
#include "../../company_base.h"
|
||||
#include "../../date_func.h"
|
||||
#include "../../timer/timer_game_calendar.h"
|
||||
#include "../../timer/timer_game_tick.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../map_func.h"
|
||||
#include "../../game/game.hpp"
|
||||
@@ -123,11 +124,11 @@ void CheckGameCompatibility(NetworkGameInfo &ngi)
|
||||
void FillStaticNetworkServerGameInfo()
|
||||
{
|
||||
_network_game_info.use_password = !_settings_client.network.server_password.empty();
|
||||
_network_game_info.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
|
||||
_network_game_info.calendar_start = TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
|
||||
_network_game_info.clients_max = _settings_client.network.max_clients;
|
||||
_network_game_info.companies_max = _settings_client.network.max_companies;
|
||||
_network_game_info.map_width = MapSizeX();
|
||||
_network_game_info.map_height = MapSizeY();
|
||||
_network_game_info.map_width = Map::SizeX();
|
||||
_network_game_info.map_height = Map::SizeY();
|
||||
_network_game_info.landscape = _settings_game.game_creation.landscape;
|
||||
_network_game_info.dedicated = _network_dedicated;
|
||||
_network_game_info.grfconfig = _grfconfig;
|
||||
@@ -140,7 +141,7 @@ void FillStaticNetworkServerGameInfo()
|
||||
* Get the NetworkServerGameInfo structure with the latest information of the server.
|
||||
* @return The current NetworkServerGameInfo.
|
||||
*/
|
||||
const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo()
|
||||
const NetworkServerGameInfo &GetCurrentNetworkServerGameInfo()
|
||||
{
|
||||
/* These variables are updated inside _network_game_info as if they are global variables:
|
||||
* - clients_on
|
||||
@@ -149,8 +150,9 @@ const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo()
|
||||
*/
|
||||
_network_game_info.companies_on = (byte)Company::GetNumItems();
|
||||
_network_game_info.spectators_on = NetworkSpectatorCount();
|
||||
_network_game_info.game_date = _date;
|
||||
return &_network_game_info;
|
||||
_network_game_info.calendar_date = TimerGameCalendar::date;
|
||||
_network_game_info.ticks_playing = TimerGameTick::counter;
|
||||
return _network_game_info;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,7 +166,7 @@ const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo()
|
||||
static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config, std::string name)
|
||||
{
|
||||
/* Find the matching GRF file */
|
||||
const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum);
|
||||
const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, &config->ident.md5sum);
|
||||
if (f == nullptr) {
|
||||
AddGRFTextToList(config->name, name.empty() ? GetString(STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN) : name);
|
||||
config->status = GCS_NOT_FOUND;
|
||||
@@ -182,9 +184,9 @@ static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config, std::strin
|
||||
* @param p the packet to write the data to.
|
||||
* @param info the NetworkGameInfo struct to serialize from.
|
||||
*/
|
||||
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool send_newgrf_names)
|
||||
void SerializeNetworkGameInfo(Packet &p, const NetworkServerGameInfo &info, bool send_newgrf_names)
|
||||
{
|
||||
p->Send_uint8 (NETWORK_GAME_INFO_VERSION);
|
||||
p.Send_uint8 (NETWORK_GAME_INFO_VERSION);
|
||||
|
||||
/*
|
||||
* Please observe the order.
|
||||
@@ -194,13 +196,16 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool
|
||||
/* Update the documentation in game_info.h on changes
|
||||
* to the NetworkGameInfo wire-protocol! */
|
||||
|
||||
/* NETWORK_GAME_INFO_VERSION = 7 */
|
||||
p.Send_uint64(info.ticks_playing);
|
||||
|
||||
/* NETWORK_GAME_INFO_VERSION = 6 */
|
||||
p->Send_uint8(send_newgrf_names ? NST_GRFID_MD5_NAME : NST_GRFID_MD5);
|
||||
p.Send_uint8(send_newgrf_names ? NST_GRFID_MD5_NAME : NST_GRFID_MD5);
|
||||
|
||||
/* NETWORK_GAME_INFO_VERSION = 5 */
|
||||
GameInfo *game_info = Game::GetInfo();
|
||||
p->Send_uint32(game_info == nullptr ? -1 : (uint32)game_info->GetVersion());
|
||||
p->Send_string(game_info == nullptr ? "" : game_info->GetName());
|
||||
p.Send_uint32(game_info == nullptr ? -1 : (uint32_t)game_info->GetVersion());
|
||||
p.Send_string(game_info == nullptr ? "" : game_info->GetName());
|
||||
|
||||
/* NETWORK_GAME_INFO_VERSION = 4 */
|
||||
{
|
||||
@@ -212,40 +217,40 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool
|
||||
uint count = 0;
|
||||
|
||||
/* Count number of GRFs to send information about */
|
||||
for (c = info->grfconfig; c != nullptr; c = c->next) {
|
||||
for (c = info.grfconfig; c != nullptr; c = c->next) {
|
||||
if (!HasBit(c->flags, GCF_STATIC)) count++;
|
||||
}
|
||||
p->Send_uint8 (count); // Send number of GRFs
|
||||
p.Send_uint8 (count); // Send number of GRFs
|
||||
|
||||
/* Send actual GRF Identifications */
|
||||
for (c = info->grfconfig; c != nullptr; c = c->next) {
|
||||
for (c = info.grfconfig; c != nullptr; c = c->next) {
|
||||
if (HasBit(c->flags, GCF_STATIC)) continue;
|
||||
|
||||
SerializeGRFIdentifier(p, &c->ident);
|
||||
if (send_newgrf_names) p->Send_string(c->GetName());
|
||||
SerializeGRFIdentifier(p, c->ident);
|
||||
if (send_newgrf_names) p.Send_string(c->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
/* NETWORK_GAME_INFO_VERSION = 3 */
|
||||
p->Send_uint32(info->game_date);
|
||||
p->Send_uint32(info->start_date);
|
||||
p.Send_uint32(info.calendar_date.base());
|
||||
p.Send_uint32(info.calendar_start.base());
|
||||
|
||||
/* NETWORK_GAME_INFO_VERSION = 2 */
|
||||
p->Send_uint8 (info->companies_max);
|
||||
p->Send_uint8 (info->companies_on);
|
||||
p->Send_uint8 (info->clients_max); // Used to be max-spectators
|
||||
p.Send_uint8 (info.companies_max);
|
||||
p.Send_uint8 (info.companies_on);
|
||||
p.Send_uint8 (info.clients_max); // Used to be max-spectators
|
||||
|
||||
/* NETWORK_GAME_INFO_VERSION = 1 */
|
||||
p->Send_string(info->server_name);
|
||||
p->Send_string(info->server_revision);
|
||||
p->Send_bool (info->use_password);
|
||||
p->Send_uint8 (info->clients_max);
|
||||
p->Send_uint8 (info->clients_on);
|
||||
p->Send_uint8 (info->spectators_on);
|
||||
p->Send_uint16(info->map_width);
|
||||
p->Send_uint16(info->map_height);
|
||||
p->Send_uint8 (info->landscape);
|
||||
p->Send_bool (info->dedicated);
|
||||
p.Send_string(info.server_name);
|
||||
p.Send_string(info.server_revision);
|
||||
p.Send_bool (info.use_password);
|
||||
p.Send_uint8 (info.clients_max);
|
||||
p.Send_uint8 (info.clients_on);
|
||||
p.Send_uint8 (info.spectators_on);
|
||||
p.Send_uint16(info.map_width);
|
||||
p.Send_uint16(info.map_height);
|
||||
p.Send_uint8 (info.landscape);
|
||||
p.Send_bool (info.dedicated);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,11 +258,9 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool
|
||||
* @param p the packet to read the data from.
|
||||
* @param info the NetworkGameInfo to deserialize into.
|
||||
*/
|
||||
void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfoNewGRFLookupTable *newgrf_lookup_table)
|
||||
void DeserializeNetworkGameInfo(Packet &p, NetworkGameInfo &info, const GameInfoNewGRFLookupTable *newgrf_lookup_table)
|
||||
{
|
||||
static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11
|
||||
|
||||
byte game_info_version = p->Recv_uint8();
|
||||
byte game_info_version = p.Recv_uint8();
|
||||
NewGRFSerializationType newgrf_serialisation = NST_GRFID_MD5;
|
||||
|
||||
/*
|
||||
@@ -269,39 +272,43 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo
|
||||
* to the NetworkGameInfo wire-protocol! */
|
||||
|
||||
switch (game_info_version) {
|
||||
case 7:
|
||||
info.ticks_playing = p.Recv_uint64();
|
||||
[[fallthrough]];
|
||||
|
||||
case 6:
|
||||
newgrf_serialisation = (NewGRFSerializationType)p->Recv_uint8();
|
||||
newgrf_serialisation = (NewGRFSerializationType)p.Recv_uint8();
|
||||
if (newgrf_serialisation >= NST_END) return;
|
||||
FALLTHROUGH;
|
||||
[[fallthrough]];
|
||||
|
||||
case 5: {
|
||||
info->gamescript_version = (int)p->Recv_uint32();
|
||||
info->gamescript_name = p->Recv_string(NETWORK_NAME_LENGTH);
|
||||
FALLTHROUGH;
|
||||
info.gamescript_version = (int)p.Recv_uint32();
|
||||
info.gamescript_name = p.Recv_string(NETWORK_NAME_LENGTH);
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
case 4: {
|
||||
GRFConfig **dst = &info->grfconfig;
|
||||
uint i;
|
||||
uint num_grfs = p->Recv_uint8();
|
||||
/* Ensure that the maximum number of NewGRFs and the field in the network
|
||||
* protocol are matched to eachother. If that is not the case anymore a
|
||||
* check must be added to ensure the received data is still valid. */
|
||||
static_assert(std::numeric_limits<uint8_t>::max() == NETWORK_MAX_GRF_COUNT);
|
||||
uint num_grfs = p.Recv_uint8();
|
||||
|
||||
/* Broken/bad data. It cannot have that many NewGRFs. */
|
||||
if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
|
||||
|
||||
for (i = 0; i < num_grfs; i++) {
|
||||
GRFConfig **dst = &info.grfconfig;
|
||||
for (uint i = 0; i < num_grfs; i++) {
|
||||
NamedGRFIdentifier grf;
|
||||
switch (newgrf_serialisation) {
|
||||
case NST_GRFID_MD5:
|
||||
DeserializeGRFIdentifier(p, &grf.ident);
|
||||
DeserializeGRFIdentifier(p, grf.ident);
|
||||
break;
|
||||
|
||||
case NST_GRFID_MD5_NAME:
|
||||
DeserializeGRFIdentifierWithName(p, &grf);
|
||||
DeserializeGRFIdentifierWithName(p, grf);
|
||||
break;
|
||||
|
||||
case NST_LOOKUP_ID: {
|
||||
if (newgrf_lookup_table == nullptr) return;
|
||||
auto it = newgrf_lookup_table->find(p->Recv_uint32());
|
||||
auto it = newgrf_lookup_table->find(p.Recv_uint32());
|
||||
if (it == newgrf_lookup_table->end()) return;
|
||||
grf = it->second;
|
||||
break;
|
||||
@@ -319,39 +326,44 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo
|
||||
*dst = c;
|
||||
dst = &c->next;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
case 3:
|
||||
info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
|
||||
info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
|
||||
FALLTHROUGH;
|
||||
info.calendar_date = Clamp(p.Recv_uint32(), 0, CalendarTime::MAX_DATE.base());
|
||||
info.calendar_start = Clamp(p.Recv_uint32(), 0, CalendarTime::MAX_DATE.base());
|
||||
[[fallthrough]];
|
||||
|
||||
case 2:
|
||||
info->companies_max = p->Recv_uint8 ();
|
||||
info->companies_on = p->Recv_uint8 ();
|
||||
p->Recv_uint8(); // Used to contain max-spectators.
|
||||
FALLTHROUGH;
|
||||
info.companies_max = p.Recv_uint8 ();
|
||||
info.companies_on = p.Recv_uint8 ();
|
||||
p.Recv_uint8(); // Used to contain max-spectators.
|
||||
[[fallthrough]];
|
||||
|
||||
case 1:
|
||||
info->server_name = p->Recv_string(NETWORK_NAME_LENGTH);
|
||||
info->server_revision = p->Recv_string(NETWORK_REVISION_LENGTH);
|
||||
if (game_info_version < 6) p->Recv_uint8 (); // Used to contain server-lang.
|
||||
info->use_password = p->Recv_bool ();
|
||||
info->clients_max = p->Recv_uint8 ();
|
||||
info->clients_on = p->Recv_uint8 ();
|
||||
info->spectators_on = p->Recv_uint8 ();
|
||||
info.server_name = p.Recv_string(NETWORK_NAME_LENGTH);
|
||||
info.server_revision = p.Recv_string(NETWORK_REVISION_LENGTH);
|
||||
if (game_info_version < 6) p.Recv_uint8 (); // Used to contain server-lang.
|
||||
info.use_password = p.Recv_bool ();
|
||||
info.clients_max = p.Recv_uint8 ();
|
||||
info.clients_on = p.Recv_uint8 ();
|
||||
info.spectators_on = p.Recv_uint8 ();
|
||||
if (game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
|
||||
info->game_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
|
||||
info->start_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
|
||||
info.calendar_date = p.Recv_uint16() + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
|
||||
info.calendar_start = p.Recv_uint16() + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
|
||||
}
|
||||
if (game_info_version < 6) while (p->Recv_uint8() != 0) {} // Used to contain the map-name.
|
||||
info->map_width = p->Recv_uint16();
|
||||
info->map_height = p->Recv_uint16();
|
||||
info->landscape = p->Recv_uint8 ();
|
||||
info->dedicated = p->Recv_bool ();
|
||||
if (game_info_version < 6) while (p.Recv_uint8() != 0) {} // Used to contain the map-name.
|
||||
info.map_width = p.Recv_uint16();
|
||||
info.map_height = p.Recv_uint16();
|
||||
info.landscape = p.Recv_uint8 ();
|
||||
info.dedicated = p.Recv_bool ();
|
||||
|
||||
if (info->landscape >= NUM_LANDSCAPE) info->landscape = 0;
|
||||
if (info.landscape >= NUM_LANDSCAPE) info.landscape = 0;
|
||||
}
|
||||
|
||||
/* For older servers, estimate the ticks running based on the calendar date. */
|
||||
if (game_info_version < 7) {
|
||||
info.ticks_playing = static_cast<uint64_t>(std::max(0, info.calendar_date.base() - info.calendar_start.base())) * Ticks::DAY_TICKS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,12 +372,11 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo
|
||||
* @param p the packet to write the data to.
|
||||
* @param grf the GRFIdentifier to serialize.
|
||||
*/
|
||||
void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf)
|
||||
void SerializeGRFIdentifier(Packet &p, const GRFIdentifier &grf)
|
||||
{
|
||||
uint j;
|
||||
p->Send_uint32(grf->grfid);
|
||||
for (j = 0; j < sizeof(grf->md5sum); j++) {
|
||||
p->Send_uint8(grf->md5sum[j]);
|
||||
p.Send_uint32(grf.grfid);
|
||||
for (size_t j = 0; j < grf.md5sum.size(); j++) {
|
||||
p.Send_uint8(grf.md5sum[j]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,12 +385,11 @@ void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf)
|
||||
* @param p the packet to read the data from.
|
||||
* @param grf the GRFIdentifier to deserialize.
|
||||
*/
|
||||
void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf)
|
||||
void DeserializeGRFIdentifier(Packet &p, GRFIdentifier &grf)
|
||||
{
|
||||
uint j;
|
||||
grf->grfid = p->Recv_uint32();
|
||||
for (j = 0; j < sizeof(grf->md5sum); j++) {
|
||||
grf->md5sum[j] = p->Recv_uint8();
|
||||
grf.grfid = p.Recv_uint32();
|
||||
for (size_t j = 0; j < grf.md5sum.size(); j++) {
|
||||
grf.md5sum[j] = p.Recv_uint8();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,8 +398,8 @@ void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf)
|
||||
* @param p the packet to read the data from.
|
||||
* @param grf the NamedGRFIdentifier to deserialize.
|
||||
*/
|
||||
void DeserializeGRFIdentifierWithName(Packet *p, NamedGRFIdentifier *grf)
|
||||
void DeserializeGRFIdentifierWithName(Packet &p, NamedGRFIdentifier &grf)
|
||||
{
|
||||
DeserializeGRFIdentifier(p, &grf->ident);
|
||||
grf->name = p->Recv_string(NETWORK_GRF_NAME_LENGTH);
|
||||
DeserializeGRFIdentifier(p, grf.ident);
|
||||
grf.name = p.Recv_string(NETWORK_GRF_NAME_LENGTH);
|
||||
}
|
||||
@@ -15,7 +15,8 @@
|
||||
#include "config.h"
|
||||
#include "core.h"
|
||||
#include "../../newgrf_config.h"
|
||||
#include "../../date_type.h"
|
||||
#include "../../timer/timer_game_calendar.h"
|
||||
#include "../../timer/timer_game_tick.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -27,6 +28,8 @@
|
||||
* Version: Bytes: Description:
|
||||
* all 1 the version of this packet's structure
|
||||
*
|
||||
* 7+ 8 amount of ticks this game has been running unpaused.
|
||||
*
|
||||
* 6+ 1 type of storage for the NewGRFs below:
|
||||
* 0 = NewGRF ID and MD5 checksum.
|
||||
* Used as default for version 5 and below, and for
|
||||
@@ -54,8 +57,8 @@
|
||||
* - 4 byte lookup table index.
|
||||
* For v6+ in case of type 2.
|
||||
*
|
||||
* 3+ 4 current game date in days since 1-1-0 (DMY)
|
||||
* 3+ 4 game introduction date in days since 1-1-0 (DMY)
|
||||
* 3+ 4 current calendar date in days since 1-1-0 (DMY)
|
||||
* 3+ 4 calendar start date in days since 1-1-0 (DMY)
|
||||
*
|
||||
* 2+ 1 maximum number of companies allowed on the server
|
||||
* 2+ 1 number of companies on the server
|
||||
@@ -92,10 +95,11 @@ enum NewGRFSerializationType {
|
||||
*/
|
||||
struct NetworkServerGameInfo {
|
||||
GRFConfig *grfconfig; ///< List of NewGRF files used
|
||||
Date start_date; ///< When the game started
|
||||
Date game_date; ///< Current date
|
||||
uint16 map_width; ///< Map width
|
||||
uint16 map_height; ///< Map height
|
||||
TimerGameCalendar::Date calendar_start; ///< When the game started.
|
||||
TimerGameCalendar::Date calendar_date; ///< Current calendar date.
|
||||
TimerGameTick::TickCounter ticks_playing; ///< Amount of ticks the game has been running unpaused.
|
||||
uint16_t map_width; ///< Map width
|
||||
uint16_t map_height; ///< Map height
|
||||
std::string server_name; ///< Server name
|
||||
std::string server_revision; ///< The version number the server is using (e.g.: 'r304' or 0.5.0)
|
||||
bool dedicated; ///< Is this a dedicated server?
|
||||
@@ -128,7 +132,7 @@ struct NamedGRFIdentifier {
|
||||
std::string name; ///< The name of the NewGRF.
|
||||
};
|
||||
/** Lookup table for the GameInfo in case of #NST_LOOKUP_ID. */
|
||||
typedef std::unordered_map<uint32, NamedGRFIdentifier> GameInfoNewGRFLookupTable;
|
||||
typedef std::unordered_map<uint32_t, NamedGRFIdentifier> GameInfoNewGRFLookupTable;
|
||||
|
||||
extern NetworkServerGameInfo _network_game_info;
|
||||
|
||||
@@ -137,13 +141,13 @@ bool IsNetworkCompatibleVersion(std::string_view other);
|
||||
void CheckGameCompatibility(NetworkGameInfo &ngi);
|
||||
|
||||
void FillStaticNetworkServerGameInfo();
|
||||
const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo();
|
||||
const NetworkServerGameInfo &GetCurrentNetworkServerGameInfo();
|
||||
|
||||
void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf);
|
||||
void DeserializeGRFIdentifierWithName(Packet *p, NamedGRFIdentifier *grf);
|
||||
void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf);
|
||||
void DeserializeGRFIdentifier(Packet &p, GRFIdentifier &grf);
|
||||
void DeserializeGRFIdentifierWithName(Packet &p, NamedGRFIdentifier &grf);
|
||||
void SerializeGRFIdentifier(Packet &p, const GRFIdentifier &grf);
|
||||
|
||||
void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfoNewGRFLookupTable *newgrf_lookup_table = nullptr);
|
||||
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool send_newgrf_names = true);
|
||||
void DeserializeNetworkGameInfo(Packet &p, NetworkGameInfo &info, const GameInfoNewGRFLookupTable *newgrf_lookup_table = nullptr);
|
||||
void SerializeNetworkGameInfo(Packet &p, const NetworkServerGameInfo &info, bool send_newgrf_names = true);
|
||||
|
||||
#endif /* NETWORK_CORE_GAME_INFO_H */
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "os_abstraction.h"
|
||||
#include "../../string_func.h"
|
||||
#include "../../3rdparty/fmt/format.h"
|
||||
#include <mutex>
|
||||
|
||||
#include "../../safeguards.h"
|
||||
@@ -80,12 +81,13 @@ const std::string &NetworkError::AsString() const
|
||||
{
|
||||
if (this->message.empty()) {
|
||||
#if defined(_WIN32)
|
||||
char buffer[512];
|
||||
if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, this->error,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer), NULL) == 0) {
|
||||
seprintf(buffer, lastof(buffer), "Unknown error %d", this->error);
|
||||
wchar_t buffer[512];
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, this->error,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, lengthof(buffer), nullptr) == 0) {
|
||||
this->message.assign(fmt::format("Unknown error {}", this->error));
|
||||
} else {
|
||||
this->message.assign(FS2OTTD(buffer));
|
||||
}
|
||||
this->message.assign(buffer);
|
||||
#else
|
||||
/* Make strerror thread safe by locking access to it. There is a thread safe strerror_r, however
|
||||
* the non-POSIX variant is available due to defining _GNU_SOURCE meaning it is not portable.
|
||||
@@ -117,8 +119,6 @@ bool NetworkError::HasError() const
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return NetworkError(WSAGetLastError());
|
||||
#elif defined(__OS2__)
|
||||
return NetworkError(sock_errno());
|
||||
#else
|
||||
return NetworkError(errno);
|
||||
#endif
|
||||
@@ -130,7 +130,7 @@ bool NetworkError::HasError() const
|
||||
* @param d The socket to set the non-blocking more for.
|
||||
* @return True if setting the non-blocking mode succeeded, otherwise false.
|
||||
*/
|
||||
bool SetNonBlocking(SOCKET d)
|
||||
bool SetNonBlocking([[maybe_unused]] SOCKET d)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
u_long nonblocking = 1;
|
||||
@@ -148,7 +148,7 @@ bool SetNonBlocking(SOCKET d)
|
||||
* @param d The socket to disable the delaying for.
|
||||
* @return True if disabling the delaying succeeded, otherwise false.
|
||||
*/
|
||||
bool SetNoDelay(SOCKET d)
|
||||
bool SetNoDelay([[maybe_unused]] SOCKET d)
|
||||
{
|
||||
int flags = 1;
|
||||
/* The (const char*) cast is needed for windows */
|
||||
|
||||
@@ -60,7 +60,7 @@ typedef unsigned long in_addr_t;
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/* UNIX stuff */
|
||||
#if defined(UNIX) && !defined(__OS2__)
|
||||
#if defined(UNIX)
|
||||
# if defined(OPENBSD) || defined(__NetBSD__)
|
||||
# define AI_ADDRCONFIG 0
|
||||
# endif
|
||||
@@ -78,15 +78,7 @@ typedef unsigned long in_addr_t;
|
||||
# include <netinet/tcp.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <net/if.h>
|
||||
/* According to glibc/NEWS, <ifaddrs.h> appeared in glibc-2.3. */
|
||||
# if !defined(__sgi__) && !defined(SUNOS) && !defined(__INNOTEK_LIBC__) \
|
||||
&& !(defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)) && !defined(__dietlibc__) && !defined(HPUX) && !defined(__ANDROID__)
|
||||
/* If for any reason ifaddrs.h does not exist on your system, comment out
|
||||
* the following two lines and an alternative way will be used to fetch
|
||||
* the list of IPs from the system. */
|
||||
# include <ifaddrs.h>
|
||||
# define HAVE_GETIFADDRS
|
||||
# endif
|
||||
# include <ifaddrs.h>
|
||||
# if !defined(INADDR_NONE)
|
||||
# define INADDR_NONE 0xffffffff
|
||||
# endif
|
||||
@@ -117,59 +109,28 @@ typedef unsigned long in_addr_t;
|
||||
|
||||
#endif /* UNIX */
|
||||
|
||||
/* OS/2 stuff */
|
||||
#if defined(__OS2__)
|
||||
# define SOCKET int
|
||||
# define INVALID_SOCKET -1
|
||||
# define closesocket close
|
||||
|
||||
/* Includes needed for OS/2 systems */
|
||||
# include <types.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <netinet/tcp.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <net/if.h>
|
||||
# include <errno.h>
|
||||
# include <sys/time.h>
|
||||
# include <netdb.h>
|
||||
# include <nerrno.h>
|
||||
# define INADDR_NONE 0xffffffff
|
||||
# include "../../3rdparty/os2/getaddrinfo.h"
|
||||
# include "../../3rdparty/os2/getnameinfo.h"
|
||||
|
||||
#define IPV6_V6ONLY 27
|
||||
|
||||
/*
|
||||
* IPv6 address
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/**
|
||||
* Emscripten doesn't set 'addrlen' for accept(), getsockname(), getpeername()
|
||||
* and recvfrom(), which confuses other functions and causes them to crash.
|
||||
* This function needs to be called after these four functions to make sure
|
||||
* 'addrlen' is patched up.
|
||||
*
|
||||
* https://github.com/emscripten-core/emscripten/issues/12996
|
||||
*
|
||||
* @param address The address returned by those four functions.
|
||||
* @return The correct value for addrlen.
|
||||
*/
|
||||
struct in6_addr {
|
||||
union {
|
||||
uint8_t __u6_addr8[16];
|
||||
uint16_t __u6_addr16[8];
|
||||
uint32_t __u6_addr32[4];
|
||||
} __u6_addr; /* 128-bit IP6 address */
|
||||
};
|
||||
inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address)
|
||||
{
|
||||
switch (address.ss_family) {
|
||||
case AF_INET6: return sizeof(struct sockaddr_in6);
|
||||
case AF_INET: return sizeof(struct sockaddr_in);
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#define s6_addr __u6_addr.__u6_addr8
|
||||
|
||||
struct sockaddr_in6 {
|
||||
uint8_t sin6_len; /* length of this struct */
|
||||
sa_family_t sin6_family; /* AF_INET6 */
|
||||
in_port_t sin6_port; /* Transport layer port # */
|
||||
uint32_t sin6_flowinfo; /* IP6 flow information */
|
||||
struct in6_addr sin6_addr; /* IP6 address */
|
||||
uint32_t sin6_scope_id; /* scope zone index */
|
||||
};
|
||||
|
||||
typedef int socklen_t;
|
||||
#if !defined(__INNOTEK_LIBC__)
|
||||
typedef unsigned long in_addr_t;
|
||||
#endif /* __INNOTEK_LIBC__ */
|
||||
|
||||
#endif /* OS/2 */
|
||||
|
||||
bool SetNonBlocking(SOCKET d);
|
||||
bool SetNoDelay(SOCKET d);
|
||||
@@ -180,8 +141,4 @@ NetworkError GetSocketError(SOCKET d);
|
||||
static_assert(sizeof(in_addr) == 4); ///< IPv4 addresses should be 4 bytes.
|
||||
static_assert(sizeof(in6_addr) == 16); ///< IPv6 addresses should be 16 bytes.
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
# include "em_proxy.h"
|
||||
#endif /* __EMSCRIPTEN__ */
|
||||
|
||||
#endif /* NETWORK_CORE_OS_ABSTRACTION_H */
|
||||
|
||||
+35
-60
@@ -28,7 +28,7 @@
|
||||
* loose some the data of the packet, so there you pass the maximum
|
||||
* size for the packet you expect from the network.
|
||||
*/
|
||||
Packet::Packet(NetworkSocketHandler *cs, size_t limit, size_t initial_read_size) : next(nullptr), pos(0), limit(limit)
|
||||
Packet::Packet(NetworkSocketHandler *cs, size_t limit, size_t initial_read_size) : pos(0), limit(limit)
|
||||
{
|
||||
assert(cs != nullptr);
|
||||
|
||||
@@ -44,45 +44,20 @@ Packet::Packet(NetworkSocketHandler *cs, size_t limit, size_t initial_read_size)
|
||||
* the limit as it might break things if the other side is not expecting
|
||||
* much larger packets than what they support.
|
||||
*/
|
||||
Packet::Packet(PacketType type, size_t limit) : next(nullptr), pos(0), limit(limit), cs(nullptr)
|
||||
Packet::Packet(PacketType type, size_t limit) : pos(0), limit(limit), cs(nullptr)
|
||||
{
|
||||
/* Allocate space for the the size so we can write that in just before sending the packet. */
|
||||
this->Send_uint16(0);
|
||||
this->Send_uint8(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given Packet to the end of the queue of packets.
|
||||
* @param queue The pointer to the begin of the queue.
|
||||
* @param packet The packet to append to the queue.
|
||||
*/
|
||||
/* static */ void Packet::AddToQueue(Packet **queue, Packet *packet)
|
||||
{
|
||||
while (*queue != nullptr) queue = &(*queue)->next;
|
||||
*queue = packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the packet from the begin of the queue and set the
|
||||
* begin of the queue to the second element in the queue.
|
||||
* @param queue The pointer to the begin of the queue.
|
||||
* @return The Packet that used to be a the begin of the queue.
|
||||
*/
|
||||
/* static */ Packet *Packet::PopFromQueue(Packet **queue)
|
||||
{
|
||||
Packet *p = *queue;
|
||||
*queue = p->next;
|
||||
p->next = nullptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes the packet size from the raw packet from packet->size
|
||||
*/
|
||||
void Packet::PrepareToSend()
|
||||
{
|
||||
assert(this->cs == nullptr && this->next == nullptr);
|
||||
assert(this->cs == nullptr);
|
||||
|
||||
this->buffer[0] = GB(this->Size(), 0, 8);
|
||||
this->buffer[1] = GB(this->Size(), 8, 8);
|
||||
@@ -103,13 +78,13 @@ bool Packet::CanWriteToPacket(size_t bytes_to_write)
|
||||
|
||||
/*
|
||||
* The next couple of functions make sure we can send
|
||||
* uint8, uint16, uint32 and uint64 endian-safe
|
||||
* uint8_t, uint16_t, uint32_t and uint64_t endian-safe
|
||||
* over the network. The least significant bytes are
|
||||
* sent first.
|
||||
*
|
||||
* So 0x01234567 would be sent as 67 45 23 01.
|
||||
*
|
||||
* A bool is sent as a uint8 where zero means false
|
||||
* A bool is sent as a uint8_t where zero means false
|
||||
* and non-zero means true.
|
||||
*/
|
||||
|
||||
@@ -126,7 +101,7 @@ void Packet::Send_bool(bool data)
|
||||
* Package a 8 bits integer in the packet.
|
||||
* @param data The data to send.
|
||||
*/
|
||||
void Packet::Send_uint8(uint8 data)
|
||||
void Packet::Send_uint8(uint8_t data)
|
||||
{
|
||||
assert(this->CanWriteToPacket(sizeof(data)));
|
||||
this->buffer.emplace_back(data);
|
||||
@@ -136,7 +111,7 @@ void Packet::Send_uint8(uint8 data)
|
||||
* Package a 16 bits integer in the packet.
|
||||
* @param data The data to send.
|
||||
*/
|
||||
void Packet::Send_uint16(uint16 data)
|
||||
void Packet::Send_uint16(uint16_t data)
|
||||
{
|
||||
assert(this->CanWriteToPacket(sizeof(data)));
|
||||
this->buffer.emplace_back(GB(data, 0, 8));
|
||||
@@ -147,7 +122,7 @@ void Packet::Send_uint16(uint16 data)
|
||||
* Package a 32 bits integer in the packet.
|
||||
* @param data The data to send.
|
||||
*/
|
||||
void Packet::Send_uint32(uint32 data)
|
||||
void Packet::Send_uint32(uint32_t data)
|
||||
{
|
||||
assert(this->CanWriteToPacket(sizeof(data)));
|
||||
this->buffer.emplace_back(GB(data, 0, 8));
|
||||
@@ -160,7 +135,7 @@ void Packet::Send_uint32(uint32 data)
|
||||
* Package a 64 bits integer in the packet.
|
||||
* @param data The data to send.
|
||||
*/
|
||||
void Packet::Send_uint64(uint64 data)
|
||||
void Packet::Send_uint64(uint64_t data)
|
||||
{
|
||||
assert(this->CanWriteToPacket(sizeof(data)));
|
||||
this->buffer.emplace_back(GB(data, 0, 8));
|
||||
@@ -191,8 +166,8 @@ void Packet::Send_string(const std::string_view data)
|
||||
*/
|
||||
void Packet::Send_buffer(const std::vector<byte> &data)
|
||||
{
|
||||
assert(this->CanWriteToPacket(sizeof(uint16) + data.size()));
|
||||
this->Send_uint16((uint16)data.size());
|
||||
assert(this->CanWriteToPacket(sizeof(uint16_t) + data.size()));
|
||||
this->Send_uint16((uint16_t)data.size());
|
||||
this->buffer.insert(this->buffer.end(), data.begin(), data.end());
|
||||
}
|
||||
|
||||
@@ -268,7 +243,7 @@ size_t Packet::Size() const
|
||||
*/
|
||||
bool Packet::ParsePacketSize()
|
||||
{
|
||||
assert(this->cs != nullptr && this->next == nullptr);
|
||||
assert(this->cs != nullptr);
|
||||
size_t size = (size_t)this->buffer[0];
|
||||
size += (size_t)this->buffer[1] << 8;
|
||||
|
||||
@@ -314,9 +289,9 @@ bool Packet::Recv_bool()
|
||||
* Read a 8 bits integer from the packet.
|
||||
* @return The read data.
|
||||
*/
|
||||
uint8 Packet::Recv_uint8()
|
||||
uint8_t Packet::Recv_uint8()
|
||||
{
|
||||
uint8 n;
|
||||
uint8_t n;
|
||||
|
||||
if (!this->CanReadFromPacket(sizeof(n), true)) return 0;
|
||||
|
||||
@@ -328,14 +303,14 @@ uint8 Packet::Recv_uint8()
|
||||
* Read a 16 bits integer from the packet.
|
||||
* @return The read data.
|
||||
*/
|
||||
uint16 Packet::Recv_uint16()
|
||||
uint16_t Packet::Recv_uint16()
|
||||
{
|
||||
uint16 n;
|
||||
uint16_t n;
|
||||
|
||||
if (!this->CanReadFromPacket(sizeof(n), true)) return 0;
|
||||
|
||||
n = (uint16)this->buffer[this->pos++];
|
||||
n += (uint16)this->buffer[this->pos++] << 8;
|
||||
n = (uint16_t)this->buffer[this->pos++];
|
||||
n += (uint16_t)this->buffer[this->pos++] << 8;
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -343,16 +318,16 @@ uint16 Packet::Recv_uint16()
|
||||
* Read a 32 bits integer from the packet.
|
||||
* @return The read data.
|
||||
*/
|
||||
uint32 Packet::Recv_uint32()
|
||||
uint32_t Packet::Recv_uint32()
|
||||
{
|
||||
uint32 n;
|
||||
uint32_t n;
|
||||
|
||||
if (!this->CanReadFromPacket(sizeof(n), true)) return 0;
|
||||
|
||||
n = (uint32)this->buffer[this->pos++];
|
||||
n += (uint32)this->buffer[this->pos++] << 8;
|
||||
n += (uint32)this->buffer[this->pos++] << 16;
|
||||
n += (uint32)this->buffer[this->pos++] << 24;
|
||||
n = (uint32_t)this->buffer[this->pos++];
|
||||
n += (uint32_t)this->buffer[this->pos++] << 8;
|
||||
n += (uint32_t)this->buffer[this->pos++] << 16;
|
||||
n += (uint32_t)this->buffer[this->pos++] << 24;
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -360,20 +335,20 @@ uint32 Packet::Recv_uint32()
|
||||
* Read a 64 bits integer from the packet.
|
||||
* @return The read data.
|
||||
*/
|
||||
uint64 Packet::Recv_uint64()
|
||||
uint64_t Packet::Recv_uint64()
|
||||
{
|
||||
uint64 n;
|
||||
uint64_t n;
|
||||
|
||||
if (!this->CanReadFromPacket(sizeof(n), true)) return 0;
|
||||
|
||||
n = (uint64)this->buffer[this->pos++];
|
||||
n += (uint64)this->buffer[this->pos++] << 8;
|
||||
n += (uint64)this->buffer[this->pos++] << 16;
|
||||
n += (uint64)this->buffer[this->pos++] << 24;
|
||||
n += (uint64)this->buffer[this->pos++] << 32;
|
||||
n += (uint64)this->buffer[this->pos++] << 40;
|
||||
n += (uint64)this->buffer[this->pos++] << 48;
|
||||
n += (uint64)this->buffer[this->pos++] << 56;
|
||||
n = (uint64_t)this->buffer[this->pos++];
|
||||
n += (uint64_t)this->buffer[this->pos++] << 8;
|
||||
n += (uint64_t)this->buffer[this->pos++] << 16;
|
||||
n += (uint64_t)this->buffer[this->pos++] << 24;
|
||||
n += (uint64_t)this->buffer[this->pos++] << 32;
|
||||
n += (uint64_t)this->buffer[this->pos++] << 40;
|
||||
n += (uint64_t)this->buffer[this->pos++] << 48;
|
||||
n += (uint64_t)this->buffer[this->pos++] << 56;
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -383,7 +358,7 @@ uint64 Packet::Recv_uint64()
|
||||
*/
|
||||
std::vector<byte> Packet::Recv_buffer()
|
||||
{
|
||||
uint16 size = this->Recv_uint16();
|
||||
uint16_t size = this->Recv_uint16();
|
||||
if (size == 0 || !this->CanReadFromPacket(size, true)) return {};
|
||||
|
||||
std::vector<byte> data;
|
||||
|
||||
+10
-17
@@ -16,11 +16,9 @@
|
||||
#include "config.h"
|
||||
#include "core.h"
|
||||
#include "../../string_type.h"
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
|
||||
typedef uint16 PacketSize; ///< Size of the whole packet.
|
||||
typedef uint8 PacketType; ///< Identifier for the packet
|
||||
typedef uint16_t PacketSize; ///< Size of the whole packet.
|
||||
typedef uint8_t PacketType; ///< Identifier for the packet
|
||||
|
||||
/**
|
||||
* Internal entity of a packet. As everything is sent as a packet,
|
||||
@@ -43,8 +41,6 @@ typedef uint8 PacketType; ///< Identifier for the packet
|
||||
*/
|
||||
struct Packet {
|
||||
private:
|
||||
/** The next packet. Used for queueing packets before sending. */
|
||||
Packet *next;
|
||||
/** The current read/write position in the packet */
|
||||
PacketSize pos;
|
||||
/** The buffer of this packet. */
|
||||
@@ -59,18 +55,15 @@ public:
|
||||
Packet(NetworkSocketHandler *cs, size_t limit, size_t initial_read_size = sizeof(PacketSize));
|
||||
Packet(PacketType type, size_t limit = COMPAT_MTU);
|
||||
|
||||
static void AddToQueue(Packet **queue, Packet *packet);
|
||||
static Packet *PopFromQueue(Packet **queue);
|
||||
|
||||
/* Sending/writing of packets */
|
||||
void PrepareToSend();
|
||||
|
||||
bool CanWriteToPacket(size_t bytes_to_write);
|
||||
void Send_bool (bool data);
|
||||
void Send_uint8 (uint8 data);
|
||||
void Send_uint16(uint16 data);
|
||||
void Send_uint32(uint32 data);
|
||||
void Send_uint64(uint64 data);
|
||||
void Send_uint8 (uint8_t data);
|
||||
void Send_uint16(uint16_t data);
|
||||
void Send_uint32(uint32_t data);
|
||||
void Send_uint64(uint64_t data);
|
||||
void Send_string(const std::string_view data);
|
||||
void Send_buffer(const std::vector<byte> &data);
|
||||
size_t Send_bytes (const byte *begin, const byte *end);
|
||||
@@ -84,10 +77,10 @@ public:
|
||||
|
||||
bool CanReadFromPacket(size_t bytes_to_read, bool close_connection = false);
|
||||
bool Recv_bool ();
|
||||
uint8 Recv_uint8 ();
|
||||
uint16 Recv_uint16();
|
||||
uint32 Recv_uint32();
|
||||
uint64 Recv_uint64();
|
||||
uint8_t Recv_uint8 ();
|
||||
uint16_t Recv_uint16();
|
||||
uint32_t Recv_uint32();
|
||||
uint64_t Recv_uint64();
|
||||
std::vector<byte> Recv_buffer();
|
||||
std::string Recv_string(size_t length, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
|
||||
|
||||
|
||||
+21
-39
@@ -22,29 +22,15 @@
|
||||
*/
|
||||
NetworkTCPSocketHandler::NetworkTCPSocketHandler(SOCKET s) :
|
||||
NetworkSocketHandler(),
|
||||
packet_queue(nullptr), packet_recv(nullptr),
|
||||
sock(s), writable(false)
|
||||
{
|
||||
}
|
||||
|
||||
NetworkTCPSocketHandler::~NetworkTCPSocketHandler()
|
||||
{
|
||||
this->EmptyPacketQueue();
|
||||
this->CloseSocket();
|
||||
}
|
||||
|
||||
/**
|
||||
* Free all pending and partially received packets.
|
||||
*/
|
||||
void NetworkTCPSocketHandler::EmptyPacketQueue()
|
||||
{
|
||||
while (this->packet_queue != nullptr) {
|
||||
delete Packet::PopFromQueue(&this->packet_queue);
|
||||
}
|
||||
delete this->packet_recv;
|
||||
this->packet_recv = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the actual socket of the connection.
|
||||
* Please make sure CloseConnection is called before CloseSocket, as
|
||||
@@ -62,12 +48,13 @@ void NetworkTCPSocketHandler::CloseSocket()
|
||||
* @param error Whether we quit under an error condition or not.
|
||||
* @return new status of the connection.
|
||||
*/
|
||||
NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection(bool error)
|
||||
NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection([[maybe_unused]] bool error)
|
||||
{
|
||||
this->MarkClosed();
|
||||
this->writable = false;
|
||||
|
||||
this->EmptyPacketQueue();
|
||||
this->packet_queue.clear();
|
||||
this->packet_recv = nullptr;
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -78,12 +65,12 @@ NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection(bool error)
|
||||
* if the OS-network-buffer is full)
|
||||
* @param packet the packet to send
|
||||
*/
|
||||
void NetworkTCPSocketHandler::SendPacket(Packet *packet)
|
||||
void NetworkTCPSocketHandler::SendPacket(std::unique_ptr<Packet> &&packet)
|
||||
{
|
||||
assert(packet != nullptr);
|
||||
|
||||
packet->PrepareToSend();
|
||||
Packet::AddToQueue(&this->packet_queue, packet);
|
||||
this->packet_queue.push_back(std::move(packet));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,15 +85,13 @@ void NetworkTCPSocketHandler::SendPacket(Packet *packet)
|
||||
*/
|
||||
SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down)
|
||||
{
|
||||
ssize_t res;
|
||||
Packet *p;
|
||||
|
||||
/* We can not write to this socket!! */
|
||||
if (!this->writable) return SPS_NONE_SENT;
|
||||
if (!this->IsConnected()) return SPS_CLOSED;
|
||||
|
||||
while ((p = this->packet_queue) != nullptr) {
|
||||
res = p->TransferOut<int>(send, this->sock, 0);
|
||||
while (!this->packet_queue.empty()) {
|
||||
Packet &p = *this->packet_queue.front();
|
||||
ssize_t res = p.TransferOut<int>(send, this->sock, 0);
|
||||
if (res == -1) {
|
||||
NetworkError err = NetworkError::GetLast();
|
||||
if (!err.WouldBlock()) {
|
||||
@@ -126,9 +111,9 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down)
|
||||
}
|
||||
|
||||
/* Is this packet sent? */
|
||||
if (p->RemainingBytesToTransfer() == 0) {
|
||||
if (p.RemainingBytesToTransfer() == 0) {
|
||||
/* Go to the next packet */
|
||||
delete Packet::PopFromQueue(&this->packet_queue);
|
||||
this->packet_queue.pop_front();
|
||||
} else {
|
||||
return SPS_PARTLY_SENT;
|
||||
}
|
||||
@@ -141,22 +126,22 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down)
|
||||
* Receives a packet for the given client
|
||||
* @return The received packet (or nullptr when it didn't receive one)
|
||||
*/
|
||||
Packet *NetworkTCPSocketHandler::ReceivePacket()
|
||||
std::unique_ptr<Packet> NetworkTCPSocketHandler::ReceivePacket()
|
||||
{
|
||||
ssize_t res;
|
||||
|
||||
if (!this->IsConnected()) return nullptr;
|
||||
|
||||
if (this->packet_recv == nullptr) {
|
||||
this->packet_recv = new Packet(this, TCP_MTU);
|
||||
this->packet_recv = std::make_unique<Packet>(this, TCP_MTU);
|
||||
}
|
||||
|
||||
Packet *p = this->packet_recv;
|
||||
Packet &p = *this->packet_recv.get();
|
||||
|
||||
/* Read packet size */
|
||||
if (!p->HasPacketSizeData()) {
|
||||
while (p->RemainingBytesToTransfer() != 0) {
|
||||
res = p->TransferIn<int>(recv, this->sock, 0);
|
||||
if (!p.HasPacketSizeData()) {
|
||||
while (p.RemainingBytesToTransfer() != 0) {
|
||||
res = p.TransferIn<int>(recv, this->sock, 0);
|
||||
if (res == -1) {
|
||||
NetworkError err = NetworkError::GetLast();
|
||||
if (!err.WouldBlock()) {
|
||||
@@ -176,15 +161,15 @@ Packet *NetworkTCPSocketHandler::ReceivePacket()
|
||||
}
|
||||
|
||||
/* Parse the size in the received packet and if not valid, close the connection. */
|
||||
if (!p->ParsePacketSize()) {
|
||||
if (!p.ParsePacketSize()) {
|
||||
this->CloseConnection();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read rest of packet */
|
||||
while (p->RemainingBytesToTransfer() != 0) {
|
||||
res = p->TransferIn<int>(recv, this->sock, 0);
|
||||
while (p.RemainingBytesToTransfer() != 0) {
|
||||
res = p.TransferIn<int>(recv, this->sock, 0);
|
||||
if (res == -1) {
|
||||
NetworkError err = NetworkError::GetLast();
|
||||
if (!err.WouldBlock()) {
|
||||
@@ -203,11 +188,8 @@ Packet *NetworkTCPSocketHandler::ReceivePacket()
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare for receiving a new packet */
|
||||
this->packet_recv = nullptr;
|
||||
|
||||
p->PrepareToRead();
|
||||
return p;
|
||||
p.PrepareToRead();
|
||||
return std::move(this->packet_recv);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+22
-9
@@ -17,7 +17,6 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
|
||||
/** The states of sending the packets. */
|
||||
@@ -31,8 +30,8 @@ enum SendPacketsState {
|
||||
/** Base socket handler for all TCP sockets */
|
||||
class NetworkTCPSocketHandler : public NetworkSocketHandler {
|
||||
private:
|
||||
Packet *packet_queue; ///< Packets that are awaiting delivery
|
||||
Packet *packet_recv; ///< Partially received packet
|
||||
std::deque<std::unique_ptr<Packet>> packet_queue; ///< Packets that are awaiting delivery. Cannot be std::queue as that does not have a clear() function.
|
||||
std::unique_ptr<Packet> packet_recv; ///< Partially received packet
|
||||
|
||||
void EmptyPacketQueue();
|
||||
public:
|
||||
@@ -48,10 +47,10 @@ public:
|
||||
virtual NetworkRecvStatus CloseConnection(bool error = true);
|
||||
void CloseSocket();
|
||||
|
||||
virtual void SendPacket(Packet *packet);
|
||||
virtual void SendPacket(std::unique_ptr<Packet> &&packet);
|
||||
SendPacketsState SendPackets(bool closing_down = false);
|
||||
|
||||
virtual Packet *ReceivePacket();
|
||||
virtual std::unique_ptr<Packet> ReceivePacket();
|
||||
|
||||
bool CanSendReceive();
|
||||
|
||||
@@ -59,7 +58,7 @@ public:
|
||||
* Whether there is something pending in the send queue.
|
||||
* @return true when something is pending in the send queue.
|
||||
*/
|
||||
bool HasSendQueue() { return this->packet_queue != nullptr; }
|
||||
bool HasSendQueue() { return !this->packet_queue.empty(); }
|
||||
|
||||
NetworkTCPSocketHandler(SOCKET s = INVALID_SOCKET);
|
||||
~NetworkTCPSocketHandler();
|
||||
@@ -101,6 +100,8 @@ private:
|
||||
NetworkAddress bind_address; ///< Address we're binding to, if any.
|
||||
int family = AF_UNSPEC; ///< Family we are using to connect with.
|
||||
|
||||
static std::vector<std::shared_ptr<TCPConnecter>> connecters; ///< List of connections that are currently being created.
|
||||
|
||||
void Resolve();
|
||||
void OnResolved(addrinfo *ai);
|
||||
bool TryNextAddress();
|
||||
@@ -115,14 +116,14 @@ private:
|
||||
|
||||
public:
|
||||
TCPConnecter() {};
|
||||
TCPConnecter(const std::string &connection_string, uint16 default_port, NetworkAddress bind_address = {}, int family = AF_UNSPEC);
|
||||
TCPConnecter(const std::string &connection_string, uint16_t default_port, const NetworkAddress &bind_address = {}, int family = AF_UNSPEC);
|
||||
virtual ~TCPConnecter();
|
||||
|
||||
/**
|
||||
* Callback when the connection succeeded.
|
||||
* @param s the socket that we opened
|
||||
*/
|
||||
virtual void OnConnect(SOCKET s) {}
|
||||
virtual void OnConnect([[maybe_unused]] SOCKET s) {}
|
||||
|
||||
/**
|
||||
* Callback for when the connection attempt failed.
|
||||
@@ -133,6 +134,18 @@ public:
|
||||
|
||||
static void CheckCallbacks();
|
||||
static void KillAll();
|
||||
|
||||
/**
|
||||
* Create the connecter, and initiate connecting by putting it in the collection of TCP connections to make.
|
||||
* @tparam T The type of connecter to create.
|
||||
* @param args The arguments to the constructor of T.
|
||||
* @return Shared pointer to the connecter.
|
||||
*/
|
||||
template <class T, typename... Args>
|
||||
static std::shared_ptr<TCPConnecter> Create(Args&& ... args)
|
||||
{
|
||||
return TCPConnecter::connecters.emplace_back(std::make_shared<T>(std::forward<Args>(args)...));
|
||||
}
|
||||
};
|
||||
|
||||
class TCPServerConnecter : public TCPConnecter {
|
||||
@@ -144,7 +157,7 @@ private:
|
||||
public:
|
||||
ServerAddress server_address; ///< Address we are connecting to.
|
||||
|
||||
TCPServerConnecter(const std::string &connection_string, uint16 default_port);
|
||||
TCPServerConnecter(const std::string &connection_string, uint16_t default_port);
|
||||
|
||||
void SetConnected(SOCKET sock);
|
||||
void SetFailure();
|
||||
|
||||
@@ -32,7 +32,7 @@ NetworkAdminSocketHandler::NetworkAdminSocketHandler(SOCKET s) : status(ADMIN_ST
|
||||
this->sock = s;
|
||||
}
|
||||
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::CloseConnection(bool error)
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::CloseConnection(bool)
|
||||
{
|
||||
delete this;
|
||||
return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||
@@ -43,11 +43,17 @@ NetworkRecvStatus NetworkAdminSocketHandler::CloseConnection(bool error)
|
||||
* @param p the packet to handle.
|
||||
* @return #NetworkRecvStatus of handling.
|
||||
*/
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p)
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet &p)
|
||||
{
|
||||
PacketAdminType type = (PacketAdminType)p->Recv_uint8();
|
||||
PacketAdminType type = (PacketAdminType)p.Recv_uint8();
|
||||
|
||||
switch (this->HasClientQuit() ? INVALID_ADMIN_PACKET : type) {
|
||||
if (this->HasClientQuit()) {
|
||||
Debug(net, 0, "[tcp/admin] Received invalid packet from '{}' ({})", this->admin_name, this->admin_version);
|
||||
this->CloseConnection();
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case ADMIN_PACKET_ADMIN_JOIN: return this->Receive_ADMIN_JOIN(p);
|
||||
case ADMIN_PACKET_ADMIN_QUIT: return this->Receive_ADMIN_QUIT(p);
|
||||
case ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY: return this->Receive_ADMIN_UPDATE_FREQUENCY(p);
|
||||
@@ -87,12 +93,7 @@ NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p)
|
||||
case ADMIN_PACKET_SERVER_PONG: return this->Receive_SERVER_PONG(p);
|
||||
|
||||
default:
|
||||
if (this->HasClientQuit()) {
|
||||
Debug(net, 0, "[tcp/admin] Received invalid packet type {} from '{}' ({})", type, this->admin_name, this->admin_version);
|
||||
} else {
|
||||
Debug(net, 0, "[tcp/admin] Received illegal packet from '{}' ({})", this->admin_name, this->admin_version);
|
||||
}
|
||||
|
||||
Debug(net, 0, "[tcp/admin] Received invalid packet type {} from '{}' ({})", type, this->admin_name, this->admin_version);
|
||||
this->CloseConnection();
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
@@ -107,10 +108,9 @@ NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p)
|
||||
*/
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::ReceivePackets()
|
||||
{
|
||||
Packet *p;
|
||||
std::unique_ptr<Packet> p;
|
||||
while ((p = this->ReceivePacket()) != nullptr) {
|
||||
NetworkRecvStatus res = this->HandlePacket(p);
|
||||
delete p;
|
||||
NetworkRecvStatus res = this->HandlePacket(*p);
|
||||
if (res != NETWORK_RECV_STATUS_OKAY) return res;
|
||||
}
|
||||
|
||||
@@ -128,40 +128,40 @@ NetworkRecvStatus NetworkAdminSocketHandler::ReceiveInvalidPacket(PacketAdminTyp
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_JOIN(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_JOIN); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_QUIT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_QUIT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_UPDATE_FREQUENCY(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_POLL); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_CHAT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_CHAT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_EXTERNAL_CHAT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_EXTERNAL_CHAT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_RCON(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_RCON); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_GAMESCRIPT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_PING(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_PING); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_JOIN(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_JOIN); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_QUIT(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_QUIT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_UPDATE_FREQUENCY(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_POLL); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_CHAT(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_CHAT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_EXTERNAL_CHAT(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_EXTERNAL_CHAT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_RCON(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_RCON); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_GAMESCRIPT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_PING(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_PING); }
|
||||
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_FULL(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_FULL); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_BANNED(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_BANNED); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_ERROR(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_ERROR); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_PROTOCOL(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_PROTOCOL); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_WELCOME(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_WELCOME); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_NEWGAME(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_NEWGAME); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_SHUTDOWN(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_SHUTDOWN); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_FULL(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_FULL); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_BANNED(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_BANNED); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_ERROR(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_ERROR); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_PROTOCOL(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_PROTOCOL); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_WELCOME(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_WELCOME); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_NEWGAME(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_NEWGAME); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_SHUTDOWN(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_SHUTDOWN); }
|
||||
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_DATE(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_DATE); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_JOIN(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_JOIN); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_INFO(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_INFO); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_UPDATE); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_QUIT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_QUIT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_ERROR(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_ERROR); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_NEW(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_NEW); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_INFO(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_INFO); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_UPDATE); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_REMOVE(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_REMOVE); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_ECONOMY(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_ECONOMY); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_STATS(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_STATS); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CHAT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CHAT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_RCON(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_RCON); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CONSOLE(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CONSOLE); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CMD_NAMES(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CMD_NAMES); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CMD_LOGGING(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CMD_LOGGING); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_RCON_END(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_RCON_END); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_PONG(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_PONG); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_DATE(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_DATE); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_JOIN(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_JOIN); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_INFO(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_INFO); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_UPDATE(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_UPDATE); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_QUIT(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_QUIT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_ERROR(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_ERROR); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_NEW(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_NEW); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_INFO(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_INFO); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_UPDATE); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_REMOVE(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_REMOVE); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_ECONOMY(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_ECONOMY); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_STATS(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_STATS); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CHAT(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CHAT); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_RCON(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_RCON); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CONSOLE(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CONSOLE); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CMD_NAMES(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CMD_NAMES); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CMD_LOGGING(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CMD_LOGGING); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_RCON_END(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_RCON_END); }
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_PONG(Packet &) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_PONG); }
|
||||
|
||||
+114
-116
@@ -21,7 +21,7 @@
|
||||
* Enum with types of TCP packets specific to the admin network.
|
||||
* This protocol may only be extended to ensure stability.
|
||||
*/
|
||||
enum PacketAdminType {
|
||||
enum PacketAdminType : uint8_t {
|
||||
ADMIN_PACKET_ADMIN_JOIN, ///< The admin announces and authenticates itself to the server.
|
||||
ADMIN_PACKET_ADMIN_QUIT, ///< The admin tells the server that it is quitting.
|
||||
ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY, ///< The admin tells the server the update frequency of a particular piece of information.
|
||||
@@ -125,56 +125,56 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_ADMIN_JOIN(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_ADMIN_JOIN(Packet &p);
|
||||
|
||||
/**
|
||||
* Notification to the server that this admin is quitting.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_ADMIN_QUIT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_ADMIN_QUIT(Packet &p);
|
||||
|
||||
/**
|
||||
* Register updates to be sent at certain frequencies (as announced in the PROTOCOL packet):
|
||||
* uint16 Update type (see #AdminUpdateType). Note integer type - see "Certain Packet Information" in docs/admin_network.md.
|
||||
* uint16 Update frequency (see #AdminUpdateFrequency), setting #ADMIN_FREQUENCY_POLL is always ignored.
|
||||
* uint16_t Update type (see #AdminUpdateType). Note integer type - see "Certain Packet Information" in docs/admin_network.md.
|
||||
* uint16_t Update frequency (see #AdminUpdateFrequency), setting #ADMIN_FREQUENCY_POLL is always ignored.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_ADMIN_UPDATE_FREQUENCY(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_ADMIN_UPDATE_FREQUENCY(Packet &p);
|
||||
|
||||
/**
|
||||
* Poll the server for certain updates, an invalid poll (e.g. not existent id) gets silently dropped:
|
||||
* uint8 #AdminUpdateType the server should answer for, only if #AdminUpdateFrequency #ADMIN_FREQUENCY_POLL is advertised in the PROTOCOL packet. Note integer type - see "Certain Packet Information" in docs/admin_network.md.
|
||||
* uint32 ID relevant to the packet type, e.g.
|
||||
* uint8_t #AdminUpdateType the server should answer for, only if #AdminUpdateFrequency #ADMIN_FREQUENCY_POLL is advertised in the PROTOCOL packet. Note integer type - see "Certain Packet Information" in docs/admin_network.md.
|
||||
* uint32_t ID relevant to the packet type, e.g.
|
||||
* - the client ID for #ADMIN_UPDATE_CLIENT_INFO. Use UINT32_MAX to show all clients.
|
||||
* - the company ID for #ADMIN_UPDATE_COMPANY_INFO. Use UINT32_MAX to show all companies.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_ADMIN_POLL(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_ADMIN_POLL(Packet &p);
|
||||
|
||||
/**
|
||||
* Send chat as the server:
|
||||
* uint8 Action such as NETWORK_ACTION_CHAT_CLIENT (see #NetworkAction).
|
||||
* uint8 Destination type such as DESTTYPE_BROADCAST (see #DestType).
|
||||
* uint32 ID of the destination such as company or client id.
|
||||
* uint8_t Action such as NETWORK_ACTION_CHAT_CLIENT (see #NetworkAction).
|
||||
* uint8_t Destination type such as DESTTYPE_BROADCAST (see #DestType).
|
||||
* uint32_t ID of the destination such as company or client id.
|
||||
* string Message.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_ADMIN_CHAT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_ADMIN_CHAT(Packet &p);
|
||||
|
||||
/**
|
||||
* Send chat from the external source:
|
||||
* string Name of the source this message came from.
|
||||
* uint16 TextColour to use for the message.
|
||||
* uint16_t TextColour to use for the message.
|
||||
* string Name of the user who sent the messsage.
|
||||
* string Message.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_ADMIN_EXTERNAL_CHAT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_ADMIN_EXTERNAL_CHAT(Packet &p);
|
||||
|
||||
/**
|
||||
* Execute a command on the servers console:
|
||||
@@ -182,7 +182,7 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_ADMIN_RCON(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_ADMIN_RCON(Packet &p);
|
||||
|
||||
/**
|
||||
* Send a JSON string to the current active GameScript.
|
||||
@@ -190,48 +190,48 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_ADMIN_GAMESCRIPT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_ADMIN_GAMESCRIPT(Packet &p);
|
||||
|
||||
/**
|
||||
* Ping the server, requiring the server to reply with a pong packet.
|
||||
* uint32 Integer value to pass to the server, which is quoted in the reply.
|
||||
* uint32_t Integer value to pass to the server, which is quoted in the reply.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_ADMIN_PING(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_ADMIN_PING(Packet &p);
|
||||
|
||||
/**
|
||||
* The server is full (connection gets closed).
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_FULL(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_FULL(Packet &p);
|
||||
|
||||
/**
|
||||
* The source IP address is banned (connection gets closed).
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_BANNED(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_BANNED(Packet &p);
|
||||
|
||||
/**
|
||||
* An error was caused by this admin connection (connection gets closed).
|
||||
* uint8 NetworkErrorCode the error caused.
|
||||
* uint8_t NetworkErrorCode the error caused.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_ERROR(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_ERROR(Packet &p);
|
||||
|
||||
/**
|
||||
* Inform a just joined admin about the protocol specifics:
|
||||
* uint8 Protocol version.
|
||||
* uint8_t Protocol version.
|
||||
* bool Further protocol data follows (repeats through all update packet types).
|
||||
* uint16 Update packet type.
|
||||
* uint16 Frequencies allowed for this update packet (bitwise).
|
||||
* uint16_t Update packet type.
|
||||
* uint16_t Frequencies allowed for this update packet (bitwise).
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_PROTOCOL(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_PROTOCOL(Packet &p);
|
||||
|
||||
/**
|
||||
* Welcome a connected admin to the game:
|
||||
@@ -239,190 +239,190 @@ protected:
|
||||
* string OpenTTD version string.
|
||||
* bool Server is dedicated.
|
||||
* string Name of the Map.
|
||||
* uint32 Random seed of the Map.
|
||||
* uint8 Landscape of the Map.
|
||||
* uint32 Start date of the Map.
|
||||
* uint16 Map width.
|
||||
* uint16 Map height.
|
||||
* uint32_t Random seed of the Map.
|
||||
* uint8_t Landscape of the Map.
|
||||
* uint32_t Start date of the Map.
|
||||
* uint16_t Map width.
|
||||
* uint16_t Map height.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_WELCOME(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_WELCOME(Packet &p);
|
||||
|
||||
/**
|
||||
* Notification about a newgame.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_NEWGAME(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_NEWGAME(Packet &p);
|
||||
|
||||
/**
|
||||
* Notification about the server shutting down.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet &p);
|
||||
|
||||
/**
|
||||
* Send the current date of the game:
|
||||
* uint32 Current game date.
|
||||
* uint32_t Current game date.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_DATE(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_DATE(Packet &p);
|
||||
|
||||
/**
|
||||
* Notification of a new client:
|
||||
* uint32 ID of the new client.
|
||||
* uint32_t ID of the new client.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_JOIN(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_JOIN(Packet &p);
|
||||
|
||||
/**
|
||||
* Client information of a specific client:
|
||||
* uint32 ID of the client.
|
||||
* uint32_t ID of the client.
|
||||
* string Network address of the client.
|
||||
* string Name of the client.
|
||||
* uint8 Language of the client.
|
||||
* uint32 Date the client joined the game.
|
||||
* uint8 ID of the company the client is playing as (255 for spectators).
|
||||
* uint8_t Language of the client.
|
||||
* uint32_t Date the client joined the game.
|
||||
* uint8_t ID of the company the client is playing as (255 for spectators).
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p);
|
||||
|
||||
/**
|
||||
* Client update details on a specific client (e.g. after rename or move):
|
||||
* uint32 ID of the client.
|
||||
* uint32_t ID of the client.
|
||||
* string Name of the client.
|
||||
* uint8 ID of the company the client is playing as (255 for spectators).
|
||||
* uint8_t ID of the company the client is playing as (255 for spectators).
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_UPDATE(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_UPDATE(Packet &p);
|
||||
|
||||
/**
|
||||
* Notification about a client leaving the game.
|
||||
* uint32 ID of the client that just left.
|
||||
* uint32_t ID of the client that just left.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_QUIT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_QUIT(Packet &p);
|
||||
|
||||
/**
|
||||
* Notification about a client error (and thus the clients disconnection).
|
||||
* uint32 ID of the client that made the error.
|
||||
* uint8 Error the client made (see NetworkErrorCode).
|
||||
* uint32_t ID of the client that made the error.
|
||||
* uint8_t Error the client made (see NetworkErrorCode).
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_ERROR(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_ERROR(Packet &p);
|
||||
|
||||
/**
|
||||
* Notification of a new company:
|
||||
* uint8 ID of the new company.
|
||||
* uint8_t ID of the new company.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_NEW(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_NEW(Packet &p);
|
||||
|
||||
/**
|
||||
* Company information on a specific company:
|
||||
* uint8 ID of the company.
|
||||
* uint8_t ID of the company.
|
||||
* string Name of the company.
|
||||
* string Name of the companies manager.
|
||||
* uint8 Main company colour.
|
||||
* uint8_t Main company colour.
|
||||
* bool Company is password protected.
|
||||
* uint32 Year the company was inaugurated.
|
||||
* uint32_t Year the company was inaugurated.
|
||||
* bool Company is an AI.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_INFO(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_INFO(Packet &p);
|
||||
|
||||
/**
|
||||
* Company information of a specific company:
|
||||
* uint8 ID of the company.
|
||||
* uint8_t ID of the company.
|
||||
* string Name of the company.
|
||||
* string Name of the companies manager.
|
||||
* uint8 Main company colour.
|
||||
* uint8_t Main company colour.
|
||||
* bool Company is password protected.
|
||||
* uint8 Quarters of bankruptcy.
|
||||
* uint8 Owner of share 1.
|
||||
* uint8 Owner of share 2.
|
||||
* uint8 Owner of share 3.
|
||||
* uint8 Owner of share 4.
|
||||
* uint8_t Quarters of bankruptcy.
|
||||
* uint8_t Owner of share 1.
|
||||
* uint8_t Owner of share 2.
|
||||
* uint8_t Owner of share 3.
|
||||
* uint8_t Owner of share 4.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_UPDATE(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_UPDATE(Packet &p);
|
||||
|
||||
/**
|
||||
* Notification about a removed company (e.g. due to bankruptcy).
|
||||
* uint8 ID of the company.
|
||||
* uint8 Reason for being removed (see #AdminCompanyRemoveReason).
|
||||
* uint8_t ID of the company.
|
||||
* uint8_t Reason for being removed (see #AdminCompanyRemoveReason).
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_REMOVE(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_REMOVE(Packet &p);
|
||||
|
||||
/**
|
||||
* Economy update of a specific company:
|
||||
* uint8 ID of the company.
|
||||
* uint64 Money.
|
||||
* uint64 Loan.
|
||||
* int64 Income.
|
||||
* uint16 Delivered cargo (this quarter).
|
||||
* uint64 Company value (last quarter).
|
||||
* uint16 Performance (last quarter).
|
||||
* uint16 Delivered cargo (last quarter).
|
||||
* uint64 Company value (previous quarter).
|
||||
* uint16 Performance (previous quarter).
|
||||
* uint16 Delivered cargo (previous quarter).
|
||||
* uint8_t ID of the company.
|
||||
* uint64_t Money.
|
||||
* uint64_t Loan.
|
||||
* int64_t Income.
|
||||
* uint16_t Delivered cargo (this quarter).
|
||||
* uint64_t Company value (last quarter).
|
||||
* uint16_t Performance (last quarter).
|
||||
* uint16_t Delivered cargo (last quarter).
|
||||
* uint64_t Company value (previous quarter).
|
||||
* uint16_t Performance (previous quarter).
|
||||
* uint16_t Delivered cargo (previous quarter).
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_ECONOMY(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_ECONOMY(Packet &p);
|
||||
|
||||
/**
|
||||
* Company statistics on stations and vehicles:
|
||||
* uint8 ID of the company.
|
||||
* uint16 Number of trains.
|
||||
* uint16 Number of lorries.
|
||||
* uint16 Number of busses.
|
||||
* uint16 Number of planes.
|
||||
* uint16 Number of ships.
|
||||
* uint16 Number of train stations.
|
||||
* uint16 Number of lorry stations.
|
||||
* uint16 Number of bus stops.
|
||||
* uint16 Number of airports and heliports.
|
||||
* uint16 Number of harbours.
|
||||
* uint8_t ID of the company.
|
||||
* uint16_t Number of trains.
|
||||
* uint16_t Number of lorries.
|
||||
* uint16_t Number of busses.
|
||||
* uint16_t Number of planes.
|
||||
* uint16_t Number of ships.
|
||||
* uint16_t Number of train stations.
|
||||
* uint16_t Number of lorry stations.
|
||||
* uint16_t Number of bus stops.
|
||||
* uint16_t Number of airports and heliports.
|
||||
* uint16_t Number of harbours.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_STATS(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_STATS(Packet &p);
|
||||
|
||||
/**
|
||||
* Send chat from the game into the admin network:
|
||||
* uint8 Action such as NETWORK_ACTION_CHAT_CLIENT (see #NetworkAction).
|
||||
* uint8 Destination type such as DESTTYPE_BROADCAST (see #DestType).
|
||||
* uint32 ID of the client who sent this message.
|
||||
* uint8_t Action such as NETWORK_ACTION_CHAT_CLIENT (see #NetworkAction).
|
||||
* uint8_t Destination type such as DESTTYPE_BROADCAST (see #DestType).
|
||||
* uint32_t ID of the client who sent this message.
|
||||
* string Message.
|
||||
* uint64 Money (only when it is a 'give money' action).
|
||||
* uint64_t Money (only when it is a 'give money' action).
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CHAT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CHAT(Packet &p);
|
||||
|
||||
/**
|
||||
* Result of an rcon command:
|
||||
* uint16 Colour as it would be used on the server or a client.
|
||||
* uint16_t Colour as it would be used on the server or a client.
|
||||
* string Output of the executed command.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_RCON(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_RCON(Packet &p);
|
||||
|
||||
/**
|
||||
* Send what would be printed on the server's console also into the admin network.
|
||||
@@ -431,7 +431,7 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CONSOLE(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CONSOLE(Packet &p);
|
||||
|
||||
/**
|
||||
* Send DoCommand names to the bot upon request only.
|
||||
@@ -445,12 +445,12 @@ protected:
|
||||
*
|
||||
* These three fields are repeated until the packet is full:
|
||||
* bool Data to follow.
|
||||
* uint16 ID of the DoCommand.
|
||||
* uint16_t ID of the DoCommand.
|
||||
* string Name of DoCommand.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CMD_NAMES(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CMD_NAMES(Packet &p);
|
||||
|
||||
/**
|
||||
* Send incoming command packets to the admin network.
|
||||
@@ -461,26 +461,24 @@ protected:
|
||||
* across different versions / revisions of OpenTTD.
|
||||
* Data provided in this packet is for logging purposes only.
|
||||
*
|
||||
* uint32 ID of the client sending the command.
|
||||
* uint8 ID of the company (0..MAX_COMPANIES-1).
|
||||
* uint16 ID of the command.
|
||||
* uint32 P1 (variable data passed to the command).
|
||||
* uint32 P2 (variable data passed to the command).
|
||||
* uint32 Tile where this is taking place.
|
||||
* string Text passed to the command.
|
||||
* uint32 Frame of execution.
|
||||
* uint32_t ID of the client sending the command.
|
||||
* uint8_t ID of the company (0..MAX_COMPANIES-1).
|
||||
* uint16_t ID of the command.
|
||||
* <var> Command specific buffer with encoded parameters of variable length.
|
||||
* The content differs per command and can change without notification.
|
||||
* uint32_t Frame of execution.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CMD_LOGGING(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CMD_LOGGING(Packet &p);
|
||||
|
||||
/**
|
||||
* Send a ping-reply (pong) to the admin that sent us the ping packet.
|
||||
* uint32 Integer identifier - should be the same as read from the admins ping packet.
|
||||
* uint32_t Integer identifier - should be the same as read from the admins ping packet.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_PONG(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_PONG(Packet &p);
|
||||
|
||||
/**
|
||||
* Notify the admin connection that the rcon command has finished.
|
||||
@@ -488,9 +486,9 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_RCON_END(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_RCON_END(Packet &p);
|
||||
|
||||
NetworkRecvStatus HandlePacket(Packet *p);
|
||||
NetworkRecvStatus HandlePacket(Packet &p);
|
||||
public:
|
||||
NetworkRecvStatus CloseConnection(bool error = true) override;
|
||||
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
#include "../network_coordinator.h"
|
||||
#include "../network_internal.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/** List of connections that are currently being created */
|
||||
static std::vector<TCPConnecter *> _tcp_connecters;
|
||||
/* static */ std::vector<std::shared_ptr<TCPConnecter>> TCPConnecter::connecters;
|
||||
|
||||
/**
|
||||
* Create a new connecter for the given address.
|
||||
@@ -29,13 +26,11 @@ static std::vector<TCPConnecter *> _tcp_connecters;
|
||||
* @param default_port If not indicated in connection_string, what port to use.
|
||||
* @param bind_address The local bind address to use. Defaults to letting the OS find one.
|
||||
*/
|
||||
TCPConnecter::TCPConnecter(const std::string &connection_string, uint16 default_port, NetworkAddress bind_address, int family) :
|
||||
TCPConnecter::TCPConnecter(const std::string &connection_string, uint16_t default_port, const NetworkAddress &bind_address, int family) :
|
||||
bind_address(bind_address),
|
||||
family(family)
|
||||
{
|
||||
this->connection_string = NormalizeConnectionString(connection_string, default_port);
|
||||
|
||||
_tcp_connecters.push_back(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +38,7 @@ TCPConnecter::TCPConnecter(const std::string &connection_string, uint16 default_
|
||||
* @param connection_string The address to connect to.
|
||||
* @param default_port If not indicated in connection_string, what port to use.
|
||||
*/
|
||||
TCPServerConnecter::TCPServerConnecter(const std::string &connection_string, uint16 default_port) :
|
||||
TCPServerConnecter::TCPServerConnecter(const std::string &connection_string, uint16_t default_port) :
|
||||
server_address(ServerAddress::Parse(connection_string, default_port))
|
||||
{
|
||||
switch (this->server_address.type) {
|
||||
@@ -59,8 +54,6 @@ TCPServerConnecter::TCPServerConnecter(const std::string &connection_string, uin
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
_tcp_connecters.push_back(this);
|
||||
}
|
||||
|
||||
TCPConnecter::~TCPConnecter()
|
||||
@@ -205,7 +198,7 @@ void TCPConnecter::OnResolved(addrinfo *ai)
|
||||
}
|
||||
|
||||
if (_debug_net_level >= 6) {
|
||||
if (this->addresses.size() == 0) {
|
||||
if (this->addresses.empty()) {
|
||||
Debug(net, 6, "{} did not resolve", this->connection_string);
|
||||
} else {
|
||||
Debug(net, 6, "{} resolved in:", this->connection_string);
|
||||
@@ -235,14 +228,13 @@ void TCPConnecter::Resolve()
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
char port_name[6];
|
||||
seprintf(port_name, lastof(port_name), "%u", address.GetPort());
|
||||
std::string port_name = std::to_string(address.GetPort());
|
||||
|
||||
static bool getaddrinfo_timeout_error_shown = false;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
addrinfo *ai;
|
||||
int error = getaddrinfo(address.GetHostname().c_str(), port_name, &hints, &ai);
|
||||
int error = getaddrinfo(address.GetHostname().c_str(), port_name.c_str(), &hints, &ai);
|
||||
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::seconds>(end - start);
|
||||
@@ -470,24 +462,14 @@ void TCPServerConnecter::SetFailure()
|
||||
*/
|
||||
/* static */ void TCPConnecter::CheckCallbacks()
|
||||
{
|
||||
for (auto iter = _tcp_connecters.begin(); iter < _tcp_connecters.end(); /* nothing */) {
|
||||
TCPConnecter *cur = *iter;
|
||||
|
||||
if (cur->CheckActivity()) {
|
||||
iter = _tcp_connecters.erase(iter);
|
||||
delete cur;
|
||||
} else {
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
TCPConnecter::connecters.erase(
|
||||
std::remove_if(TCPConnecter::connecters.begin(), TCPConnecter::connecters.end(),
|
||||
[](auto &connecter) { return connecter->CheckActivity(); }),
|
||||
TCPConnecter::connecters.end());
|
||||
}
|
||||
|
||||
/** Kill all connection attempts. */
|
||||
/* static */ void TCPConnecter::KillAll()
|
||||
{
|
||||
for (auto iter = _tcp_connecters.begin(); iter < _tcp_connecters.end(); /* nothing */) {
|
||||
TCPConnecter *cur = *iter;
|
||||
iter = _tcp_connecters.erase(iter);
|
||||
delete cur;
|
||||
}
|
||||
TCPConnecter::connecters.clear();
|
||||
}
|
||||
|
||||
@@ -49,11 +49,11 @@ bool ContentInfo::IsValid() const
|
||||
/**
|
||||
* Search a textfile file next to this file in the content list.
|
||||
* @param type The type of the textfile to search for.
|
||||
* @return The filename for the textfile, \c nullptr otherwise.
|
||||
* @return The filename for the textfile.
|
||||
*/
|
||||
const char *ContentInfo::GetTextfile(TextfileType type) const
|
||||
std::optional<std::string> ContentInfo::GetTextfile(TextfileType type) const
|
||||
{
|
||||
if (this->state == INVALID) return nullptr;
|
||||
if (this->state == INVALID) return std::nullopt;
|
||||
const char *tmp;
|
||||
switch (this->type) {
|
||||
default: NOT_REACHED();
|
||||
@@ -70,8 +70,8 @@ const char *ContentInfo::GetTextfile(TextfileType type) const
|
||||
tmp = Game::GetScannerLibrary()->FindMainScript(this, true);
|
||||
break;
|
||||
case CONTENT_TYPE_NEWGRF: {
|
||||
const GRFConfig *gc = FindGRFConfig(BSWAP32(this->unique_id), FGCM_EXACT, this->md5sum);
|
||||
tmp = gc != nullptr ? gc->filename : nullptr;
|
||||
const GRFConfig *gc = FindGRFConfig(BSWAP32(this->unique_id), FGCM_EXACT, &this->md5sum);
|
||||
tmp = gc != nullptr ? gc->filename.c_str() : nullptr;
|
||||
break;
|
||||
}
|
||||
case CONTENT_TYPE_BASE_GRAPHICS:
|
||||
@@ -85,11 +85,10 @@ const char *ContentInfo::GetTextfile(TextfileType type) const
|
||||
break;
|
||||
case CONTENT_TYPE_SCENARIO:
|
||||
case CONTENT_TYPE_HEIGHTMAP:
|
||||
extern const char *FindScenario(const ContentInfo *ci, bool md5sum);
|
||||
tmp = FindScenario(this, true);
|
||||
break;
|
||||
}
|
||||
if (tmp == nullptr) return nullptr;
|
||||
if (tmp == nullptr) return std::nullopt;
|
||||
return ::GetTextfile(type, GetContentInfoSubDir(this->type), tmp);
|
||||
}
|
||||
|
||||
@@ -99,9 +98,9 @@ const char *ContentInfo::GetTextfile(TextfileType type) const
|
||||
* @param p the packet to handle
|
||||
* @return true if we should immediately handle further packets, false otherwise
|
||||
*/
|
||||
bool NetworkContentSocketHandler::HandlePacket(Packet *p)
|
||||
bool NetworkContentSocketHandler::HandlePacket(Packet &p)
|
||||
{
|
||||
PacketContentType type = (PacketContentType)p->Recv_uint8();
|
||||
PacketContentType type = (PacketContentType)p.Recv_uint8();
|
||||
|
||||
switch (this->HasClientQuit() ? PACKET_CONTENT_END : type) {
|
||||
case PACKET_CONTENT_CLIENT_INFO_LIST: return this->Receive_CLIENT_INFO_LIST(p);
|
||||
@@ -147,12 +146,11 @@ bool NetworkContentSocketHandler::ReceivePackets()
|
||||
*
|
||||
* What arbitrary number to choose is the ultimate question though.
|
||||
*/
|
||||
Packet *p;
|
||||
std::unique_ptr<Packet> p;
|
||||
static const int MAX_PACKETS_TO_RECEIVE = 42;
|
||||
int i = MAX_PACKETS_TO_RECEIVE;
|
||||
while (--i != 0 && (p = this->ReceivePacket()) != nullptr) {
|
||||
bool cont = this->HandlePacket(p);
|
||||
delete p;
|
||||
bool cont = this->HandlePacket(*p);
|
||||
if (!cont) return true;
|
||||
}
|
||||
|
||||
@@ -171,13 +169,13 @@ bool NetworkContentSocketHandler::ReceiveInvalidPacket(PacketContentType type)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkContentSocketHandler::Receive_CLIENT_INFO_LIST(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_LIST); }
|
||||
bool NetworkContentSocketHandler::Receive_CLIENT_INFO_ID(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_ID); }
|
||||
bool NetworkContentSocketHandler::Receive_CLIENT_INFO_EXTID(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_EXTID); }
|
||||
bool NetworkContentSocketHandler::Receive_CLIENT_INFO_EXTID_MD5(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_EXTID_MD5); }
|
||||
bool NetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_INFO); }
|
||||
bool NetworkContentSocketHandler::Receive_CLIENT_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_CONTENT); }
|
||||
bool NetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_CONTENT); }
|
||||
bool NetworkContentSocketHandler::Receive_CLIENT_INFO_LIST(Packet &) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_LIST); }
|
||||
bool NetworkContentSocketHandler::Receive_CLIENT_INFO_ID(Packet &) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_ID); }
|
||||
bool NetworkContentSocketHandler::Receive_CLIENT_INFO_EXTID(Packet &) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_EXTID); }
|
||||
bool NetworkContentSocketHandler::Receive_CLIENT_INFO_EXTID_MD5(Packet &) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_EXTID_MD5); }
|
||||
bool NetworkContentSocketHandler::Receive_SERVER_INFO(Packet &) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_INFO); }
|
||||
bool NetworkContentSocketHandler::Receive_CLIENT_CONTENT(Packet &) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_CONTENT); }
|
||||
bool NetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet &) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_CONTENT); }
|
||||
|
||||
/**
|
||||
* Helper to get the subdirectory a #ContentInfo is located in.
|
||||
|
||||
@@ -26,94 +26,94 @@ protected:
|
||||
/**
|
||||
* Client requesting a list of content info:
|
||||
* byte type
|
||||
* uint32 openttd version (or 0xFFFFFFFF if using a list)
|
||||
* uint32_t openttd version (or 0xFFFFFFFF if using a list)
|
||||
* Only if the above value is 0xFFFFFFFF:
|
||||
* uint8 count
|
||||
* uint8_t count
|
||||
* string branch-name ("vanilla" for upstream OpenTTD)
|
||||
* string release version (like "12.0")
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_CLIENT_INFO_LIST(Packet *p);
|
||||
virtual bool Receive_CLIENT_INFO_LIST(Packet &p);
|
||||
|
||||
/**
|
||||
* Client requesting a list of content info:
|
||||
* uint16 count of ids
|
||||
* uint32 id (count times)
|
||||
* uint16_t count of ids
|
||||
* uint32_t id (count times)
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_CLIENT_INFO_ID(Packet *p);
|
||||
virtual bool Receive_CLIENT_INFO_ID(Packet &p);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* uint8_t count of requests
|
||||
* for each request:
|
||||
* uint8 type
|
||||
* unique id (uint32)
|
||||
* uint8_t type
|
||||
* unique id (uint32_t)
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_CLIENT_INFO_EXTID(Packet *p);
|
||||
virtual bool Receive_CLIENT_INFO_EXTID(Packet &p);
|
||||
|
||||
/**
|
||||
* Client requesting a list of content info based on an external
|
||||
* 'unique' id; GRF ID + MD5 checksum for NewGRFS, shortname and
|
||||
* xor-ed MD5 checksums for base graphics and AIs.
|
||||
* Scenarios and AI libraries are not supported
|
||||
* uint8 count of requests
|
||||
* uint8_t count of requests
|
||||
* for each request:
|
||||
* uint8 type
|
||||
* unique id (uint32)
|
||||
* uint8_t type
|
||||
* unique id (uint32_t)
|
||||
* md5 (16 bytes)
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_CLIENT_INFO_EXTID_MD5(Packet *p);
|
||||
virtual bool Receive_CLIENT_INFO_EXTID_MD5(Packet &p);
|
||||
|
||||
/**
|
||||
* Server sending list of content info:
|
||||
* byte type (invalid ID == does not exist)
|
||||
* uint32 id
|
||||
* uint32 file_size
|
||||
* uint32_t id
|
||||
* uint32_t 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
|
||||
* uint32_t unique id
|
||||
* uint8_t md5sum (16 bytes)
|
||||
* uint8_t dependency count
|
||||
* uint32_t unique id of dependency (dependency count times)
|
||||
* uint8_t tag count
|
||||
* string tag (max 32 characters for tag count times)
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_SERVER_INFO(Packet *p);
|
||||
virtual bool Receive_SERVER_INFO(Packet &p);
|
||||
|
||||
/**
|
||||
* Client requesting the actual content:
|
||||
* uint16 count of unique ids
|
||||
* uint32 unique id (count times)
|
||||
* uint16_t count of unique ids
|
||||
* uint32_t unique id (count times)
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_CLIENT_CONTENT(Packet *p);
|
||||
virtual bool Receive_CLIENT_CONTENT(Packet &p);
|
||||
|
||||
/**
|
||||
* Server sending list of content info:
|
||||
* uint32 unique id
|
||||
* uint32 file size (0 == does not exist)
|
||||
* uint32_t unique id
|
||||
* uint32_t 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.
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_SERVER_CONTENT(Packet *p);
|
||||
virtual bool Receive_SERVER_CONTENT(Packet &p);
|
||||
|
||||
bool HandlePacket(Packet *p);
|
||||
bool HandlePacket(Packet &p);
|
||||
public:
|
||||
/**
|
||||
* Create a new cs socket handler for a given cs
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#ifndef NETWORK_CORE_TCP_CONTENT_TYPE_H
|
||||
#define NETWORK_CORE_TCP_CONTENT_TYPE_H
|
||||
|
||||
#include "../../3rdparty/md5/md5.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
|
||||
@@ -30,7 +32,7 @@ enum ContentType {
|
||||
};
|
||||
|
||||
/** Enum with all types of TCP content packets. The order MUST not be changed **/
|
||||
enum PacketContentType {
|
||||
enum PacketContentType : uint8_t {
|
||||
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
|
||||
@@ -60,14 +62,14 @@ struct ContentInfo {
|
||||
|
||||
ContentType type = INVALID_CONTENT_TYPE; ///< Type of content
|
||||
ContentID id = INVALID_CONTENT_ID; ///< Unique (server side) ID for the content
|
||||
uint32 filesize = 0; ///< Size of the file
|
||||
uint32_t filesize = 0; ///< Size of the file
|
||||
std::string filename; ///< Filename (for the .tar.gz; only valid on download)
|
||||
std::string name; ///< Name of the content
|
||||
std::string version; ///< Version of the content
|
||||
std::string url; ///< URL related to the content
|
||||
std::string description; ///< Description of the content
|
||||
uint32 unique_id = 0; ///< Unique ID; either GRF ID or shortname
|
||||
byte md5sum[16] = {0}; ///< The MD5 checksum
|
||||
uint32_t unique_id = 0; ///< Unique ID; either GRF ID or shortname
|
||||
MD5Hash md5sum; ///< The MD5 checksum
|
||||
std::vector<ContentID> dependencies; ///< The dependencies (unique server side ids)
|
||||
StringList tags; ///< Tags associated with the content
|
||||
State state = State::UNSELECTED; ///< Whether the content info is selected (for download)
|
||||
@@ -75,7 +77,7 @@ struct ContentInfo {
|
||||
|
||||
bool IsSelected() const;
|
||||
bool IsValid() const;
|
||||
const char *GetTextfile(TextfileType type) const;
|
||||
std::optional<std::string> GetTextfile(TextfileType type) const;
|
||||
};
|
||||
|
||||
#endif /* NETWORK_CORE_TCP_CONTENT_TYPE_H */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../date_func.h"
|
||||
#include "../../timer/timer_game_calendar.h"
|
||||
#include "../../debug.h"
|
||||
#include "tcp_coordinator.h"
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
* @param p The packet to handle.
|
||||
* @return True iff we should immediately handle further packets.
|
||||
*/
|
||||
bool NetworkCoordinatorSocketHandler::HandlePacket(Packet *p)
|
||||
bool NetworkCoordinatorSocketHandler::HandlePacket(Packet &p)
|
||||
{
|
||||
PacketCoordinatorType type = (PacketCoordinatorType)p->Recv_uint8();
|
||||
PacketCoordinatorType type = (PacketCoordinatorType)p.Recv_uint8();
|
||||
|
||||
switch (type) {
|
||||
case PACKET_COORDINATOR_GC_ERROR: return this->Receive_GC_ERROR(p);
|
||||
@@ -64,12 +64,11 @@ bool NetworkCoordinatorSocketHandler::ReceivePackets()
|
||||
*
|
||||
* What arbitrary number to choose is the ultimate question though.
|
||||
*/
|
||||
Packet *p;
|
||||
std::unique_ptr<Packet> p;
|
||||
static const int MAX_PACKETS_TO_RECEIVE = 42;
|
||||
int i = MAX_PACKETS_TO_RECEIVE;
|
||||
while (--i != 0 && (p = this->ReceivePacket()) != nullptr) {
|
||||
bool cont = this->HandlePacket(p);
|
||||
delete p;
|
||||
bool cont = this->HandlePacket(*p);
|
||||
if (!cont) return true;
|
||||
}
|
||||
|
||||
@@ -87,20 +86,20 @@ bool NetworkCoordinatorSocketHandler::ReceiveInvalidPacket(PacketCoordinatorType
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_ERROR); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_SERVER_REGISTER(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERVER_REGISTER); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_REGISTER_ACK); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_SERVER_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERVER_UPDATE); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_CLIENT_LISTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_LISTING); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_LISTING); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_CLIENT_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_CONNECT); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_CONNECTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_CONNECTING); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_SERCLI_CONNECT_FAILED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERCLI_CONNECT_FAILED); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_CONNECT_FAILED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_CONNECT_FAILED); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_CLIENT_CONNECTED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_CONNECTED); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_DIRECT_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_DIRECT_CONNECT); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_STUN_REQUEST(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_STUN_REQUEST); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_SERCLI_STUN_RESULT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERCLI_STUN_RESULT); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_STUN_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_STUN_CONNECT); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_NEWGRF_LOOKUP(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_NEWGRF_LOOKUP); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_TURN_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_TURN_CONNECT); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_ERROR); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_SERVER_REGISTER(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERVER_REGISTER); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_REGISTER_ACK); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_SERVER_UPDATE(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERVER_UPDATE); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_CLIENT_LISTING(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_LISTING); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_LISTING); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_CLIENT_CONNECT(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_CONNECT); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_CONNECTING(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_CONNECTING); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_SERCLI_CONNECT_FAILED(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERCLI_CONNECT_FAILED); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_CONNECT_FAILED(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_CONNECT_FAILED); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_CLIENT_CONNECTED(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_CONNECTED); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_DIRECT_CONNECT(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_DIRECT_CONNECT); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_STUN_REQUEST(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_STUN_REQUEST); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_SERCLI_STUN_RESULT(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERCLI_STUN_RESULT); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_STUN_CONNECT(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_STUN_CONNECT); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_NEWGRF_LOOKUP(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_NEWGRF_LOOKUP); }
|
||||
bool NetworkCoordinatorSocketHandler::Receive_GC_TURN_CONNECT(Packet &) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_TURN_CONNECT); }
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "os_abstraction.h"
|
||||
#include "tcp.h"
|
||||
#include "packet.h"
|
||||
#include "game_info.h"
|
||||
#include "network_game_info.h"
|
||||
|
||||
/**
|
||||
* Enum with all types of TCP Game Coordinator packets. The order MUST not be changed.
|
||||
@@ -25,7 +25,7 @@
|
||||
* CLIENT -> packets from Client to Game Coordinator.
|
||||
* SERCLI -> packets from either the Server or Client to Game Coordinator.
|
||||
**/
|
||||
enum PacketCoordinatorType {
|
||||
enum PacketCoordinatorType : uint8_t {
|
||||
PACKET_COORDINATOR_GC_ERROR, ///< Game Coordinator indicates there was an error.
|
||||
PACKET_COORDINATOR_SERVER_REGISTER, ///< Server registration.
|
||||
PACKET_COORDINATOR_GC_REGISTER_ACK, ///< Game Coordinator accepts the registration.
|
||||
@@ -77,71 +77,71 @@ protected:
|
||||
* permanent error causing the connection to be dropped, or in response
|
||||
* to a request that is invalid.
|
||||
*
|
||||
* uint8 Type of error (see NetworkCoordinatorErrorType).
|
||||
* uint8_t Type of error (see NetworkCoordinatorErrorType).
|
||||
* string Details of the error.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_GC_ERROR(Packet *p);
|
||||
virtual bool Receive_GC_ERROR(Packet &p);
|
||||
|
||||
/**
|
||||
* Server is starting a multiplayer game and wants to let the
|
||||
* Game Coordinator know.
|
||||
*
|
||||
* uint8 Game Coordinator protocol version.
|
||||
* uint8 Type of game (see ServerGameType).
|
||||
* uint16 Local port of the server.
|
||||
* uint8_t Game Coordinator protocol version.
|
||||
* uint8_t Type of game (see ServerGameType).
|
||||
* uint16_t Local port of the server.
|
||||
* string Invite code the server wants to use (can be empty; coordinator will assign a new invite code).
|
||||
* string Secret that belongs to the invite code (empty if invite code is empty).
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_SERVER_REGISTER(Packet *p);
|
||||
virtual bool Receive_SERVER_REGISTER(Packet &p);
|
||||
|
||||
/**
|
||||
* Game Coordinator acknowledges the registration.
|
||||
*
|
||||
* string Invite code that can be used to join this server.
|
||||
* string Secret that belongs to the invite code (only needed if reusing the invite code on next SERVER_REGISTER).
|
||||
* uint8 Type of connection was detected (see ConnectionType).
|
||||
* uint8_t Type of connection was detected (see ConnectionType).
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_GC_REGISTER_ACK(Packet *p);
|
||||
virtual bool Receive_GC_REGISTER_ACK(Packet &p);
|
||||
|
||||
/**
|
||||
* Send an update of the current state of the server to the Game Coordinator.
|
||||
*
|
||||
* uint8 Game Coordinator protocol version.
|
||||
* uint8_t Game Coordinator protocol version.
|
||||
* Serialized NetworkGameInfo. See game_info.hpp for details.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_SERVER_UPDATE(Packet *p);
|
||||
virtual bool Receive_SERVER_UPDATE(Packet &p);
|
||||
|
||||
/**
|
||||
* Client requests a list of all public servers.
|
||||
*
|
||||
* uint8 Game Coordinator protocol version.
|
||||
* uint8 Game-info version used by this client.
|
||||
* uint8_t Game Coordinator protocol version.
|
||||
* uint8_t Game-info version used by this client.
|
||||
* string Revision of the client.
|
||||
* uint32 (Game Coordinator protocol >= 4) Cursor as received from GC_NEWGRF_LOOKUP, or zero.
|
||||
* uint32_t (Game Coordinator protocol >= 4) Cursor as received from GC_NEWGRF_LOOKUP, or zero.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_CLIENT_LISTING(Packet *p);
|
||||
virtual bool Receive_CLIENT_LISTING(Packet &p);
|
||||
|
||||
/**
|
||||
* Game Coordinator replies with a list of all public servers. Multiple
|
||||
* of these packets are received after a request till all servers are
|
||||
* sent over. Last packet will have server count of 0.
|
||||
*
|
||||
* uint16 Amount of public servers in this packet.
|
||||
* uint16_t Amount of public servers in this packet.
|
||||
* For each server:
|
||||
* string Connection string for this server.
|
||||
* Serialized NetworkGameInfo. See game_info.hpp for details.
|
||||
@@ -149,18 +149,18 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_GC_LISTING(Packet *p);
|
||||
virtual bool Receive_GC_LISTING(Packet &p);
|
||||
|
||||
/**
|
||||
* Client wants to connect to a Server.
|
||||
*
|
||||
* uint8 Game Coordinator protocol version.
|
||||
* uint8_t Game Coordinator protocol version.
|
||||
* string Invite code of the Server to join.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_CLIENT_CONNECT(Packet *p);
|
||||
virtual bool Receive_CLIENT_CONNECT(Packet &p);
|
||||
|
||||
/**
|
||||
* Game Coordinator informs the Client under what token it will start the
|
||||
@@ -172,19 +172,19 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_GC_CONNECTING(Packet *p);
|
||||
virtual bool Receive_GC_CONNECTING(Packet &p);
|
||||
|
||||
/**
|
||||
* Client or Server failed to connect to the remote side.
|
||||
*
|
||||
* uint8 Game Coordinator protocol version.
|
||||
* uint8_t Game Coordinator protocol version.
|
||||
* string Token to track the current connect request.
|
||||
* uint8 Tracking number to track current connect request.
|
||||
* uint8_t Tracking number to track current connect request.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_SERCLI_CONNECT_FAILED(Packet *p);
|
||||
virtual bool Receive_SERCLI_CONNECT_FAILED(Packet &p);
|
||||
|
||||
/**
|
||||
* Game Coordinator informs the Client that it failed to find a way to
|
||||
@@ -196,33 +196,33 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_GC_CONNECT_FAILED(Packet *p);
|
||||
virtual bool Receive_GC_CONNECT_FAILED(Packet &p);
|
||||
|
||||
/**
|
||||
* Client informs the Game Coordinator the connection with the Server is
|
||||
* established. The Client will disconnect from the Game Coordinator next.
|
||||
*
|
||||
* uint8 Game Coordinator protocol version.
|
||||
* uint8_t Game Coordinator protocol version.
|
||||
* string Token to track the current connect request.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_CLIENT_CONNECTED(Packet *p);
|
||||
virtual bool Receive_CLIENT_CONNECTED(Packet &p);
|
||||
|
||||
/**
|
||||
* Game Coordinator requests that the Client makes a direct connection to
|
||||
* the indicated peer, which is a Server.
|
||||
*
|
||||
* string Token to track the current connect request.
|
||||
* uint8 Tracking number to track current connect request.
|
||||
* uint8_t Tracking number to track current connect request.
|
||||
* string Hostname of the peer.
|
||||
* uint16 Port of the peer.
|
||||
* uint16_t Port of the peer.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_GC_DIRECT_CONNECT(Packet *p);
|
||||
virtual bool Receive_GC_DIRECT_CONNECT(Packet &p);
|
||||
|
||||
/**
|
||||
* Game Coordinator requests the client/server to do a STUN request to the
|
||||
@@ -237,20 +237,20 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_GC_STUN_REQUEST(Packet *p);
|
||||
virtual bool Receive_GC_STUN_REQUEST(Packet &p);
|
||||
|
||||
/**
|
||||
* Client/server informs the Game Coordinator the result of a STUN request.
|
||||
*
|
||||
* uint8 Game Coordinator protocol version.
|
||||
* uint8_t Game Coordinator protocol version.
|
||||
* string Token to track the current connect request.
|
||||
* uint8 Interface number, as given during STUN request.
|
||||
* uint8_t Interface number, as given during STUN request.
|
||||
* bool Whether the STUN connection was successful.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_SERCLI_STUN_RESULT(Packet *p);
|
||||
virtual bool Receive_SERCLI_STUN_RESULT(Packet &p);
|
||||
|
||||
/**
|
||||
* Game Coordinator informs the client/server of its STUN peer (the host:ip
|
||||
@@ -258,25 +258,25 @@ protected:
|
||||
* the local address as used with the STUN request.
|
||||
*
|
||||
* string Token to track the current connect request.
|
||||
* uint8 Tracking number to track current connect request.
|
||||
* uint8 Interface number, as given during STUN request.
|
||||
* uint8_t Tracking number to track current connect request.
|
||||
* uint8_t Interface number, as given during STUN request.
|
||||
* string Host of the peer.
|
||||
* uint16 Port of the peer.
|
||||
* uint16_t Port of the peer.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_GC_STUN_CONNECT(Packet *p);
|
||||
virtual bool Receive_GC_STUN_CONNECT(Packet &p);
|
||||
|
||||
/**
|
||||
* Game Coordinator informs the client of updates for the NewGRFs lookup table
|
||||
* as used by the NewGRF deserialization in GC_LISTING.
|
||||
* This packet is sent after a CLIENT_LISTING request, but before GC_LISTING.
|
||||
*
|
||||
* uint32 Lookup table cursor.
|
||||
* uint16 Number of NewGRFs in the packet, with for each of the NewGRFs:
|
||||
* uint32 Lookup table index for the NewGRF.
|
||||
* uint32 Unique NewGRF ID.
|
||||
* uint32_t Lookup table cursor.
|
||||
* uint16_t Number of NewGRFs in the packet, with for each of the NewGRFs:
|
||||
* uint32_t Lookup table index for the NewGRF.
|
||||
* uint32_t Unique NewGRF ID.
|
||||
* byte[16] MD5 checksum of the NewGRF
|
||||
* string Name of the NewGRF.
|
||||
*
|
||||
@@ -289,23 +289,23 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_GC_NEWGRF_LOOKUP(Packet *p);
|
||||
virtual bool Receive_GC_NEWGRF_LOOKUP(Packet &p);
|
||||
|
||||
/**
|
||||
* Game Coordinator requests that we make a connection to the indicated
|
||||
* peer, which is a TURN server.
|
||||
*
|
||||
* string Token to track the current connect request.
|
||||
* uint8 Tracking number to track current connect request.
|
||||
* uint8_t Tracking number to track current connect request.
|
||||
* string Ticket to hand over to the TURN server.
|
||||
* string Connection string of the TURN server.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_GC_TURN_CONNECT(Packet *p);
|
||||
virtual bool Receive_GC_TURN_CONNECT(Packet &p);
|
||||
|
||||
bool HandlePacket(Packet *p);
|
||||
bool HandlePacket(Packet &p);
|
||||
public:
|
||||
/**
|
||||
* Create a new cs socket handler for a given cs.
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
static std::vector<std::unique_ptr<NetworkGameSocketHandler>> _deferred_deletions;
|
||||
|
||||
/**
|
||||
* Create a new socket for the game connection.
|
||||
* @param s The socket to connect with.
|
||||
@@ -38,11 +40,10 @@ NetworkGameSocketHandler::NetworkGameSocketHandler(SOCKET s) : info(nullptr), cl
|
||||
* For servers: close connection and that is it
|
||||
* @return the new status
|
||||
*/
|
||||
NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool error)
|
||||
NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool)
|
||||
{
|
||||
/* Clients drop back to the main menu */
|
||||
if (!_network_server && _networking) {
|
||||
extern void ClientNetworkEmergencySave(); // from network_client.cpp
|
||||
ClientNetworkEmergencySave();
|
||||
_switch_mode = SM_MENU;
|
||||
_networking = false;
|
||||
@@ -60,13 +61,19 @@ NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool error)
|
||||
* @param p the packet to handle
|
||||
* @return #NetworkRecvStatus of handling.
|
||||
*/
|
||||
NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet *p)
|
||||
NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet &p)
|
||||
{
|
||||
PacketGameType type = (PacketGameType)p->Recv_uint8();
|
||||
PacketGameType type = (PacketGameType)p.Recv_uint8();
|
||||
|
||||
if (this->HasClientQuit()) {
|
||||
Debug(net, 0, "[tcp/game] Received invalid packet from client {}", this->client_id);
|
||||
this->CloseConnection();
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
|
||||
this->last_packet = std::chrono::steady_clock::now();
|
||||
|
||||
switch (this->HasClientQuit() ? PACKET_END : type) {
|
||||
switch (type) {
|
||||
case PACKET_SERVER_FULL: return this->Receive_SERVER_FULL(p);
|
||||
case PACKET_SERVER_BANNED: return this->Receive_SERVER_BANNED(p);
|
||||
case PACKET_CLIENT_JOIN: return this->Receive_CLIENT_JOIN(p);
|
||||
@@ -113,13 +120,8 @@ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet *p)
|
||||
case PACKET_SERVER_CONFIG_UPDATE: return this->Receive_SERVER_CONFIG_UPDATE(p);
|
||||
|
||||
default:
|
||||
Debug(net, 0, "[tcp/game] Received invalid packet type {} from client {}", type, this->client_id);
|
||||
this->CloseConnection();
|
||||
|
||||
if (this->HasClientQuit()) {
|
||||
Debug(net, 0, "[tcp/game] Received invalid packet type {} from client {}", type, this->client_id);
|
||||
} else {
|
||||
Debug(net, 0, "[tcp/game] Received illegal packet from client {}", this->client_id);
|
||||
}
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
}
|
||||
@@ -133,10 +135,9 @@ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet *p)
|
||||
*/
|
||||
NetworkRecvStatus NetworkGameSocketHandler::ReceivePackets()
|
||||
{
|
||||
Packet *p;
|
||||
std::unique_ptr<Packet> p;
|
||||
while ((p = this->ReceivePacket()) != nullptr) {
|
||||
NetworkRecvStatus res = HandlePacket(p);
|
||||
delete p;
|
||||
NetworkRecvStatus res = HandlePacket(*p);
|
||||
if (res != NETWORK_RECV_STATUS_OKAY) return res;
|
||||
}
|
||||
|
||||
@@ -154,47 +155,59 @@ NetworkRecvStatus NetworkGameSocketHandler::ReceiveInvalidPacket(PacketGameType
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_FULL(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_FULL); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_BANNED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_BANNED); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_JOIN); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_INFO); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_GAME_INFO); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CLIENT_INFO); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_GAME_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_COMPANY_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMPANY_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WELCOME); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GETMAP); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WAIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WAIT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_BEGIN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_BEGIN); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_SIZE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_SIZE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_DATA(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_DATA); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_DONE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_MAP_OK); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_JOIN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_JOIN); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_FRAME); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SYNC(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SYNC); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ACK(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ACK); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMMAND); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMMAND); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_CHAT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CHAT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_EXTERNAL_CHAT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_EXTERNAL_CHAT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SET_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SET_NAME); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_QUIT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ERROR); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_QUIT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR_QUIT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SHUTDOWN); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEWGAME(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEWGAME); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_RCON(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_RCON); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_RCON); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CHECK_NEWGRFS); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_NEWGRFS_CHECKED); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MOVE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MOVE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_MOVE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMPANY_UPDATE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CONFIG_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CONFIG_UPDATE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_FULL(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_FULL); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_BANNED(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_BANNED); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_JOIN); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_INFO(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_INFO); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_GAME_INFO); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_CLIENT_INFO); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_GAME_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_COMPANY_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMPANY_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_WELCOME); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GETMAP); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WAIT(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_WAIT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_BEGIN(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_BEGIN); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_SIZE(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_SIZE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_DATA(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_DATA); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_DONE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_MAP_OK); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_JOIN(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_JOIN); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_FRAME(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_FRAME); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SYNC(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_SYNC); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ACK(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ACK); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMMAND); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMMAND); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_CHAT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CHAT(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_CHAT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_EXTERNAL_CHAT(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_EXTERNAL_CHAT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SET_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SET_NAME); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_QUIT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ERROR); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_QUIT(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_QUIT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR_QUIT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_SHUTDOWN); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEWGAME(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEWGAME); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_RCON(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_RCON); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_RCON(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_RCON); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_CHECK_NEWGRFS); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_NEWGRFS_CHECKED); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MOVE(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_MOVE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_MOVE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMPANY_UPDATE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CONFIG_UPDATE(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_CONFIG_UPDATE); }
|
||||
|
||||
void NetworkGameSocketHandler::DeferDeletion()
|
||||
{
|
||||
_deferred_deletions.emplace_back(this);
|
||||
this->is_pending_deletion = true;
|
||||
}
|
||||
|
||||
/* static */ void NetworkGameSocketHandler::ProcessDeferredDeletions()
|
||||
{
|
||||
/* Calls deleter on all items */
|
||||
_deferred_deletions.clear();
|
||||
}
|
||||
|
||||
+122
-132
@@ -22,7 +22,7 @@
|
||||
* Enum with all types of TCP packets.
|
||||
* For the exact meaning, look at #NetworkGameSocketHandler.
|
||||
*/
|
||||
enum PacketGameType {
|
||||
enum PacketGameType : uint8_t {
|
||||
/*
|
||||
* These first four pair of packets (thus eight in
|
||||
* total) must remain in this order for backward
|
||||
@@ -131,30 +131,19 @@ enum PacketGameType {
|
||||
/** Packet that wraps a command */
|
||||
struct CommandPacket;
|
||||
|
||||
/** A queue of CommandPackets. */
|
||||
class CommandQueue {
|
||||
CommandPacket *first; ///< The first packet in the queue.
|
||||
CommandPacket *last; ///< The last packet in the queue; only valid when first != nullptr.
|
||||
uint count; ///< The number of items in the queue.
|
||||
|
||||
public:
|
||||
/** Initialise the command queue. */
|
||||
CommandQueue() : first(nullptr), last(nullptr), count(0) {}
|
||||
/** Clear the command queue. */
|
||||
~CommandQueue() { this->Free(); }
|
||||
void Append(CommandPacket *p);
|
||||
CommandPacket *Pop(bool ignore_paused = false);
|
||||
CommandPacket *Peek(bool ignore_paused = false);
|
||||
void Free();
|
||||
/** Get the number of items in the queue. */
|
||||
uint Count() const { return this->count; }
|
||||
};
|
||||
/**
|
||||
* A "queue" of CommandPackets.
|
||||
* Not a std::queue because, when paused, some commands remain on the queue.
|
||||
* In other words, you do not always pop the first element from this queue.
|
||||
*/
|
||||
using CommandQueue = std::vector<CommandPacket>;
|
||||
|
||||
/** Base socket handler for all TCP sockets */
|
||||
class NetworkGameSocketHandler : public NetworkTCPSocketHandler {
|
||||
/* TODO: rewrite into a proper class */
|
||||
private:
|
||||
NetworkClientInfo *info; ///< Client info related to this socket
|
||||
NetworkClientInfo *info; ///< Client info related to this socket
|
||||
bool is_pending_deletion = false; ///< Whether this socket is pending deletion
|
||||
|
||||
protected:
|
||||
NetworkRecvStatus ReceiveInvalidPacket(PacketGameType type);
|
||||
@@ -163,293 +152,289 @@ protected:
|
||||
* Notification that the server is full.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_FULL(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_FULL(Packet &p);
|
||||
|
||||
/**
|
||||
* Notification that the client trying to join is banned.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_BANNED(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_BANNED(Packet &p);
|
||||
|
||||
/**
|
||||
* Try to join the server:
|
||||
* string OpenTTD revision (norev000 if no revision).
|
||||
* string Name of the client (max NETWORK_NAME_LENGTH).
|
||||
* uint8 ID of the company to play as (1..MAX_COMPANIES).
|
||||
* uint8 ID of the clients Language.
|
||||
* uint8_t ID of the company to play as (1..MAX_COMPANIES).
|
||||
* uint8_t ID of the clients Language.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_JOIN(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_JOIN(Packet &p);
|
||||
|
||||
/**
|
||||
* The client made an error:
|
||||
* uint8 Error code caused (see NetworkErrorCode).
|
||||
* uint8_t Error code caused (see NetworkErrorCode).
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_ERROR(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_ERROR(Packet &p);
|
||||
|
||||
/**
|
||||
* Request game information.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_GAME_INFO(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_GAME_INFO(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends information about the game.
|
||||
* Serialized NetworkGameInfo. See game_info.h for details.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_GAME_INFO(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_GAME_INFO(Packet &p);
|
||||
|
||||
/**
|
||||
* Send information about a client:
|
||||
* uint32 ID of the client (always unique on a server. 1 = server, 0 is invalid).
|
||||
* uint8 ID of the company the client is playing as (255 for spectators).
|
||||
* uint32_t ID of the client (always unique on a server. 1 = server, 0 is invalid).
|
||||
* uint8_t ID of the company the client is playing as (255 for spectators).
|
||||
* string Name of the client.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p);
|
||||
|
||||
/**
|
||||
* Indication to the client that the server needs a game password.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet &p);
|
||||
|
||||
/**
|
||||
* Indication to the client that the server needs a company password:
|
||||
* uint32 Generation seed.
|
||||
* uint32_t Generation seed.
|
||||
* string Network ID of the server.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p);
|
||||
|
||||
/**
|
||||
* Send a password to the server to authorize:
|
||||
* uint8 Password type (see NetworkPasswordType).
|
||||
* uint8_t Password type (see NetworkPasswordType).
|
||||
* string The password.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet &p);
|
||||
|
||||
/**
|
||||
* Send a password to the server to authorize
|
||||
* uint8 Password type (see NetworkPasswordType).
|
||||
* uint8_t Password type (see NetworkPasswordType).
|
||||
* string The password.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet &p);
|
||||
|
||||
/**
|
||||
* The client is joined and ready to receive their map:
|
||||
* uint32 Own client ID.
|
||||
* uint32 Generation seed.
|
||||
* uint32_t Own client ID.
|
||||
* uint32_t Generation seed.
|
||||
* string Network ID of the server.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_WELCOME(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_WELCOME(Packet &p);
|
||||
|
||||
/**
|
||||
* Request the map from the server.
|
||||
* uint32 NewGRF version (release versions of OpenTTD only).
|
||||
* uint32_t NewGRF version (release versions of OpenTTD only).
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_GETMAP(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_GETMAP(Packet &p);
|
||||
|
||||
/**
|
||||
* Notification that another client is currently receiving the map:
|
||||
* uint8 Number of clients waiting in front of you.
|
||||
* uint8_t Number of clients waiting in front of you.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_WAIT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_WAIT(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends that the server will begin with sending the map to the client:
|
||||
* uint32 Current frame.
|
||||
* uint32_t Current frame.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends the size of the map to the client.
|
||||
* uint32 Size of the (compressed) map (in bytes).
|
||||
* uint32_t Size of the (compressed) map (in bytes).
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_MAP_SIZE(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_MAP_SIZE(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends the data of the map to the client:
|
||||
* Contains a part of the map (until max size of packet).
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_MAP_DATA(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_MAP_DATA(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends that all data of the map are sent to the client:
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_MAP_DONE(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_MAP_DONE(Packet &p);
|
||||
|
||||
/**
|
||||
* Tell the server that we are done receiving/loading the map.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet &p);
|
||||
|
||||
/**
|
||||
* A client joined (PACKET_CLIENT_MAP_OK), what usually directly follows is a PACKET_SERVER_CLIENT_INFO:
|
||||
* uint32 ID of the client that just joined the game.
|
||||
* uint32_t ID of the client that just joined the game.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_JOIN(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_JOIN(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends the current frame counter to the client:
|
||||
* uint32 Frame counter
|
||||
* uint32 Frame counter max (how far may the client walk before the server?)
|
||||
* uint32 General seed 1 (dependent on compile settings, not default).
|
||||
* uint32 General seed 2 (dependent on compile settings, not default).
|
||||
* uint8 Random token to validate the client is actually listening (only occasionally present).
|
||||
* uint32_t Frame counter
|
||||
* uint32_t Frame counter max (how far may the client walk before the server?)
|
||||
* uint32_t General seed 1 (dependent on compile settings, not default).
|
||||
* uint32_t General seed 2 (dependent on compile settings, not default).
|
||||
* uint8_t Random token to validate the client is actually listening (only occasionally present).
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_FRAME(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_FRAME(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends a sync-check to the client:
|
||||
* uint32 Frame counter.
|
||||
* uint32 General seed 1.
|
||||
* uint32 General seed 2 (dependent on compile settings, not default).
|
||||
* uint32_t Frame counter.
|
||||
* uint32_t General seed 1.
|
||||
* uint32_t General seed 2 (dependent on compile settings, not default).
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_SYNC(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_SYNC(Packet &p);
|
||||
|
||||
/**
|
||||
* Tell the server we are done with this frame:
|
||||
* uint32 Current frame counter of the client.
|
||||
* uint8 The random token that the server sent in the PACKET_SERVER_FRAME packet.
|
||||
* uint32_t Current frame counter of the client.
|
||||
* uint8_t The random token that the server sent in the PACKET_SERVER_FRAME packet.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_ACK(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_ACK(Packet &p);
|
||||
|
||||
/**
|
||||
* Send a DoCommand to the Server:
|
||||
* uint8 ID of the company (0..MAX_COMPANIES-1).
|
||||
* uint32 ID of the command (see command.h).
|
||||
* uint32 P1 (free variables used in DoCommand).
|
||||
* uint32 P2
|
||||
* uint32 Tile where this is taking place.
|
||||
* string Text.
|
||||
* uint8 ID of the callback.
|
||||
* uint8_t ID of the company (0..MAX_COMPANIES-1).
|
||||
* uint32_t ID of the command (see command.h).
|
||||
* <var> Command specific buffer with encoded parameters of variable length.
|
||||
* The content differs per command and can change without notification.
|
||||
* uint8_t ID of the callback.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_COMMAND(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_COMMAND(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends a DoCommand to the client:
|
||||
* uint8 ID of the company (0..MAX_COMPANIES-1).
|
||||
* uint32 ID of the command (see command.h).
|
||||
* uint32 P1 (free variable used in DoCommand).
|
||||
* uint32 P2.
|
||||
* uint32 Tile where this is taking place.
|
||||
* string Text.
|
||||
* uint8 ID of the callback.
|
||||
* uint32 Frame of execution.
|
||||
* uint8_t ID of the company (0..MAX_COMPANIES-1).
|
||||
* uint32_t ID of the command (see command.h).
|
||||
* <var> Command specific buffer with encoded parameters of variable length.
|
||||
* The content differs per command and can change without notification.
|
||||
* uint8_t ID of the callback.
|
||||
* uint32_t Frame of execution.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMMAND(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMMAND(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends a chat-packet to the server:
|
||||
* uint8 ID of the action (see NetworkAction).
|
||||
* uint8 ID of the destination type (see DestType).
|
||||
* uint32 ID of the client or company (destination of the chat).
|
||||
* uint8_t ID of the action (see NetworkAction).
|
||||
* uint8_t ID of the destination type (see DestType).
|
||||
* uint32_t ID of the client or company (destination of the chat).
|
||||
* string Message (max NETWORK_CHAT_LENGTH).
|
||||
* uint64 data (used e.g. for 'give money' actions).
|
||||
* uint64_t data (used e.g. for 'give money' actions).
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_CHAT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_CHAT(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends a chat-packet to the client:
|
||||
* uint8 ID of the action (see NetworkAction).
|
||||
* uint32 ID of the client (origin of the chat).
|
||||
* uint8_t ID of the action (see NetworkAction).
|
||||
* uint32_t ID of the client (origin of the chat).
|
||||
* string Message (max NETWORK_CHAT_LENGTH).
|
||||
* uint64 data (used e.g. for 'give money' actions).
|
||||
* uint64_t data (used e.g. for 'give money' actions).
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CHAT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CHAT(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends a chat-packet for external source to the client:
|
||||
* string Name of the source this message came from.
|
||||
* uint16 TextColour to use for the message.
|
||||
* uint16_t TextColour to use for the message.
|
||||
* string Name of the user who sent the messsage.
|
||||
* string Message (max NETWORK_CHAT_LENGTH).
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_EXTERNAL_CHAT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_EXTERNAL_CHAT(Packet &p);
|
||||
|
||||
/**
|
||||
* Set the password for the clients current company:
|
||||
* string The password.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_SET_PASSWORD(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_SET_PASSWORD(Packet &p);
|
||||
|
||||
/**
|
||||
* Gives the client a new name:
|
||||
* string New name of the client.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_SET_NAME(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_SET_NAME(Packet &p);
|
||||
|
||||
/**
|
||||
* The client is quitting the game.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_QUIT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_QUIT(Packet &p);
|
||||
|
||||
/**
|
||||
* The client made an error and is quitting the game.
|
||||
* uint8 Error of the code caused (see NetworkErrorCode).
|
||||
* uint8_t Error of the code caused (see NetworkErrorCode).
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_ERROR(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_ERROR(Packet &p);
|
||||
|
||||
/**
|
||||
* Notification that a client left the game:
|
||||
* uint32 ID of the client.
|
||||
* uint32_t ID of the client.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_QUIT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_QUIT(Packet &p);
|
||||
|
||||
/**
|
||||
* Inform all clients that one client made an error and thus has quit/been disconnected:
|
||||
* uint32 ID of the client that caused the error.
|
||||
* uint8 Code of the error caused (see NetworkErrorCode).
|
||||
* uint32_t ID of the client that caused the error.
|
||||
* uint8_t Code of the error caused (see NetworkErrorCode).
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet &p);
|
||||
|
||||
/**
|
||||
* Let the clients know that the server is closing.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet &p);
|
||||
|
||||
/**
|
||||
* Let the clients know that the server is loading a new map.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_NEWGAME(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_NEWGAME(Packet &p);
|
||||
|
||||
/**
|
||||
* Send the result of an issues RCon command back to the client:
|
||||
* uint16 Colour code.
|
||||
* uint16_t Colour code.
|
||||
* string Output of the RCon command
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_RCON(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_RCON(Packet &p);
|
||||
|
||||
/**
|
||||
* Send an RCon command to the server:
|
||||
@@ -457,61 +442,61 @@ protected:
|
||||
* string Command to be executed.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_RCON(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_RCON(Packet &p);
|
||||
|
||||
/**
|
||||
* Sends information about all used GRFs to the client:
|
||||
* uint8 Amount of GRFs (the following data is repeated this many times, i.e. per GRF data).
|
||||
* uint32 GRF ID
|
||||
* 16 * uint8 MD5 checksum of the GRF
|
||||
* uint8_t Amount of GRFs (the following data is repeated this many times, i.e. per GRF data).
|
||||
* uint32_t GRF ID
|
||||
* 16 * uint8_t MD5 checksum of the GRF
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CHECK_NEWGRFS(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CHECK_NEWGRFS(Packet &p);
|
||||
|
||||
/**
|
||||
* Tell the server that we have the required GRFs
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_NEWGRFS_CHECKED(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_NEWGRFS_CHECKED(Packet &p);
|
||||
|
||||
/**
|
||||
* Move a client from one company into another:
|
||||
* uint32 ID of the client.
|
||||
* uint8 ID of the new company.
|
||||
* uint32_t ID of the client.
|
||||
* uint8_t ID of the new company.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_MOVE(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_MOVE(Packet &p);
|
||||
|
||||
/**
|
||||
* Request the server to move this client into another company:
|
||||
* uint8 ID of the company the client wants to join.
|
||||
* uint8_t ID of the company the client wants to join.
|
||||
* string Password, if the company is password protected.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_MOVE(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_MOVE(Packet &p);
|
||||
|
||||
/**
|
||||
* Update the clients knowledge of which company is password protected:
|
||||
* uint16 Bitwise representation of each company
|
||||
* uint16_t Bitwise representation of each company
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_UPDATE(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_COMPANY_UPDATE(Packet &p);
|
||||
|
||||
/**
|
||||
* Update the clients knowledge of the max settings:
|
||||
* uint8 Maximum number of companies allowed.
|
||||
* uint8 Maximum number of spectators allowed.
|
||||
* uint8_t Maximum number of companies allowed.
|
||||
* uint8_t Maximum number of spectators allowed.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_CONFIG_UPDATE(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_CONFIG_UPDATE(Packet &p);
|
||||
|
||||
NetworkRecvStatus HandlePacket(Packet *p);
|
||||
NetworkRecvStatus HandlePacket(Packet &p);
|
||||
|
||||
NetworkGameSocketHandler(SOCKET s);
|
||||
public:
|
||||
ClientID client_id; ///< Client identifier
|
||||
uint32 last_frame; ///< Last frame we have executed
|
||||
uint32 last_frame_server; ///< Last frame the server has executed
|
||||
uint32_t last_frame; ///< Last frame we have executed
|
||||
uint32_t last_frame_server; ///< Last frame the server has executed
|
||||
CommandQueue incoming_queue; ///< The command-queue awaiting handling
|
||||
std::chrono::steady_clock::time_point last_packet; ///< Time we received the last frame.
|
||||
|
||||
@@ -522,7 +507,7 @@ public:
|
||||
* @param status The reason the connection got closed.
|
||||
*/
|
||||
virtual NetworkRecvStatus CloseConnection(NetworkRecvStatus status) = 0;
|
||||
virtual ~NetworkGameSocketHandler() {}
|
||||
virtual ~NetworkGameSocketHandler() = default;
|
||||
|
||||
/**
|
||||
* Sets the client info for this socket handler.
|
||||
@@ -545,8 +530,13 @@ public:
|
||||
|
||||
NetworkRecvStatus ReceivePackets();
|
||||
|
||||
const char *ReceiveCommand(Packet *p, CommandPacket *cp);
|
||||
void SendCommand(Packet *p, const CommandPacket *cp);
|
||||
const char *ReceiveCommand(Packet &p, CommandPacket &cp);
|
||||
void SendCommand(Packet &p, const CommandPacket &cp);
|
||||
|
||||
bool IsPendingDeletion() const { return this->is_pending_deletion; }
|
||||
|
||||
void DeferDeletion();
|
||||
static void ProcessDeferredDeletions();
|
||||
};
|
||||
|
||||
#endif /* NETWORK_CORE_TCP_GAME_H */
|
||||
|
||||
@@ -1,322 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../rev.h"
|
||||
#include "../network_internal.h"
|
||||
#include "game_info.h"
|
||||
|
||||
#include "tcp_http.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/** List of open HTTP connections. */
|
||||
static std::vector<NetworkHTTPSocketHandler *> _http_connections;
|
||||
|
||||
/**
|
||||
* Start the querying
|
||||
* @param s the socket of this connection
|
||||
* @param callback the callback for HTTP retrieval
|
||||
* @param host the hostname of the server to connect to
|
||||
* @param url the url at the server
|
||||
* @param data the data to send
|
||||
* @param depth the depth (redirect recursion) of the queries
|
||||
*/
|
||||
NetworkHTTPSocketHandler::NetworkHTTPSocketHandler(SOCKET s,
|
||||
HTTPCallback *callback, const std::string &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)
|
||||
{
|
||||
Debug(net, 5, "[tcp/http] Requesting {}{}", host, url);
|
||||
std::string request;
|
||||
if (data != nullptr) {
|
||||
request = fmt::format("POST {} HTTP/1.0\r\nHost: {}\r\nUser-Agent: OpenTTD/{}\r\nContent-Type: text/plain\r\nContent-Length: {}\r\n\r\n{}\r\n", url, host, GetNetworkRevisionString(), strlen(data), data);
|
||||
} else {
|
||||
request = fmt::format("GET {} HTTP/1.0\r\nHost: {}\r\nUser-Agent: OpenTTD/{}\r\n\r\n", url, host, GetNetworkRevisionString());
|
||||
}
|
||||
|
||||
ssize_t res = send(this->sock, request.data(), (int)request.size(), 0);
|
||||
if (res != (ssize_t)request.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;
|
||||
return;
|
||||
}
|
||||
|
||||
_http_connections.push_back(this);
|
||||
}
|
||||
|
||||
/** Free whatever needs to be freed. */
|
||||
NetworkHTTPSocketHandler::~NetworkHTTPSocketHandler()
|
||||
{
|
||||
this->CloseSocket();
|
||||
|
||||
free(this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the actual socket of the connection.
|
||||
*/
|
||||
void NetworkHTTPSocketHandler::CloseSocket()
|
||||
{
|
||||
if (this->sock != INVALID_SOCKET) closesocket(this->sock);
|
||||
this->sock = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to simplify the error handling.
|
||||
* @param msg the error message to show.
|
||||
*/
|
||||
#define return_error(msg) { Debug(net, 1, 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 occurred. Downloading failed.
|
||||
* @note if an error occurred 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) != nullptr);
|
||||
|
||||
/* 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 == nullptr) 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 {} 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, 1, "[tcp/http] Unhandled status reply {}", 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 == nullptr) 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, 7, "[tcp/http] Redirecting to {}", uri);
|
||||
|
||||
int ret = NetworkHTTPSocketHandler::Connect(uri, this->callback, this->data, this->redirect_depth + 1);
|
||||
if (ret != 0) return ret;
|
||||
|
||||
/* We've relinquished control of data now. */
|
||||
this->data = nullptr;
|
||||
|
||||
/* Restore the header. */
|
||||
*end_of_line = '\r';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 NetworkHTTPSocketHandler::Connect(char *uri, HTTPCallback *callback, const char *data, int depth)
|
||||
{
|
||||
char *hname = strstr(uri, "://");
|
||||
if (hname == nullptr) return_error("[tcp/http] Invalid location");
|
||||
|
||||
hname += 3;
|
||||
|
||||
char *url = strchr(hname, '/');
|
||||
if (url == nullptr) return_error("[tcp/http] Invalid location");
|
||||
|
||||
*url = '\0';
|
||||
|
||||
std::string hostname = std::string(hname);
|
||||
|
||||
/* Restore the URL. */
|
||||
*url = '/';
|
||||
new NetworkHTTPContentConnecter(hostname, 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) {
|
||||
NetworkError err = NetworkError::GetLast();
|
||||
if (!err.WouldBlock()) {
|
||||
/* Something went wrong... */
|
||||
if (!err.IsConnectionReset()) Debug(net, 0, "Recv failed: {}", err.AsString());
|
||||
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(nullptr, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait till we read the end-of-header identifier */
|
||||
if (this->recv_length == 0) {
|
||||
ssize_t read = this->recv_pos + res;
|
||||
ssize_t end = std::min<ssize_t>(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 == nullptr) {
|
||||
if (read == lengthof(this->recv_buffer)) {
|
||||
Debug(net, 1, "[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 = std::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 = std::min<ssize_t>(this->recv_length, res);
|
||||
/* Receive whatever we're expecting. */
|
||||
this->callback->OnReceiveData(this->recv_buffer, res);
|
||||
this->recv_length -= res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the receiving for all HTTP connections.
|
||||
*/
|
||||
/* static */ void NetworkHTTPSocketHandler::HTTPReceive()
|
||||
{
|
||||
/* No connections, just bail out. */
|
||||
if (_http_connections.size() == 0) return;
|
||||
|
||||
fd_set read_fd;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&read_fd);
|
||||
for (NetworkHTTPSocketHandler *handler : _http_connections) {
|
||||
FD_SET(handler->sock, &read_fd);
|
||||
}
|
||||
|
||||
tv.tv_sec = tv.tv_usec = 0; // don't block at all.
|
||||
int n = select(FD_SETSIZE, &read_fd, nullptr, nullptr, &tv);
|
||||
if (n == -1) return;
|
||||
|
||||
for (auto 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->CloseSocket();
|
||||
iter = _http_connections.erase(iter);
|
||||
delete cur;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* 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 "tcp.h"
|
||||
|
||||
/** Callback for when the HTTP handler has something to tell us. */
|
||||
struct HTTPCallback {
|
||||
/**
|
||||
* An error has occurred 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, nullptr when all data has been received.
|
||||
* @param length the amount of received data, 0 when all data has been received.
|
||||
* @note When nullptr is sent the HTTP socket handler is closed/freed.
|
||||
*/
|
||||
virtual void OnReceiveData(const char *data, size_t length) = 0;
|
||||
|
||||
/** Silentium */
|
||||
virtual ~HTTPCallback() {}
|
||||
};
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
void CloseSocket();
|
||||
|
||||
NetworkHTTPSocketHandler(SOCKET sock, HTTPCallback *callback,
|
||||
const std::string &host, const char *url, const char *data, int depth);
|
||||
|
||||
~NetworkHTTPSocketHandler();
|
||||
|
||||
static int Connect(char *uri, HTTPCallback *callback,
|
||||
const char *data = nullptr, int depth = 0);
|
||||
|
||||
static void HTTPReceive();
|
||||
};
|
||||
|
||||
/** Connect with a HTTP server and do ONE query. */
|
||||
class NetworkHTTPContentConnecter : TCPConnecter {
|
||||
std::string hostname; ///< Hostname we are connecting to.
|
||||
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 hostname The hostname 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 std::string &hostname, HTTPCallback *callback, const char *url, const char *data = nullptr, int depth = 0) :
|
||||
TCPConnecter(hostname, 80),
|
||||
hostname(hostname),
|
||||
callback(callback),
|
||||
url(stredup(url)),
|
||||
data(data),
|
||||
depth(depth)
|
||||
{
|
||||
}
|
||||
|
||||
/** Free all our allocated data. */
|
||||
~NetworkHTTPContentConnecter()
|
||||
{
|
||||
free(this->url);
|
||||
}
|
||||
|
||||
void OnFailure() override
|
||||
{
|
||||
this->callback->OnFailure();
|
||||
free(this->data);
|
||||
}
|
||||
|
||||
void OnConnect(SOCKET s) override
|
||||
{
|
||||
new NetworkHTTPSocketHandler(s, this->callback, this->hostname, this->url, this->data, this->depth);
|
||||
/* We've relinquished control of data now. */
|
||||
this->data = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* NETWORK_CORE_TCP_HTTP_H */
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
|
||||
/* take care of listener port */
|
||||
for (auto &s : sockets) {
|
||||
FD_SET(s.second, &read_fd);
|
||||
FD_SET(s.first, &read_fd);
|
||||
}
|
||||
|
||||
tv.tv_sec = tv.tv_usec = 0; // don't block at all.
|
||||
@@ -119,7 +119,7 @@ public:
|
||||
|
||||
/* accept clients.. */
|
||||
for (auto &s : sockets) {
|
||||
if (FD_ISSET(s.second, &read_fd)) AcceptClient(s.second);
|
||||
if (FD_ISSET(s.first, &read_fd)) AcceptClient(s.first);
|
||||
}
|
||||
|
||||
/* read stuff from clients */
|
||||
@@ -137,9 +137,9 @@ public:
|
||||
* @param port The port to listen on.
|
||||
* @return true if listening succeeded.
|
||||
*/
|
||||
static bool Listen(uint16 port)
|
||||
static bool Listen(uint16_t port)
|
||||
{
|
||||
assert(sockets.size() == 0);
|
||||
assert(sockets.empty());
|
||||
|
||||
NetworkAddressList addresses;
|
||||
GetBindAddresses(&addresses, port);
|
||||
@@ -148,7 +148,7 @@ public:
|
||||
address.Listen(SOCK_STREAM, &sockets);
|
||||
}
|
||||
|
||||
if (sockets.size() == 0) {
|
||||
if (sockets.empty()) {
|
||||
Debug(net, 0, "Could not start network: could not create listening socket");
|
||||
ShowNetworkError(STR_NETWORK_ERROR_SERVER_START);
|
||||
return false;
|
||||
@@ -161,7 +161,7 @@ public:
|
||||
static void CloseListeners()
|
||||
{
|
||||
for (auto &s : sockets) {
|
||||
closesocket(s.second);
|
||||
closesocket(s.first);
|
||||
}
|
||||
sockets.clear();
|
||||
Debug(net, 5, "[{}] Closed listeners", Tsocket::GetName());
|
||||
|
||||
@@ -26,4 +26,4 @@ bool NetworkStunSocketHandler::ReceiveInvalidPacket(PacketStunType type)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkStunSocketHandler::Receive_SERCLI_STUN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_STUN_SERCLI_STUN); }
|
||||
bool NetworkStunSocketHandler::Receive_SERCLI_STUN(Packet &) { return this->ReceiveInvalidPacket(PACKET_STUN_SERCLI_STUN); }
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "packet.h"
|
||||
|
||||
/** Enum with all types of TCP STUN packets. The order MUST not be changed. **/
|
||||
enum PacketStunType {
|
||||
enum PacketStunType : uint8_t {
|
||||
PACKET_STUN_SERCLI_STUN, ///< Send a STUN request to the STUN server.
|
||||
PACKET_STUN_END, ///< Must ALWAYS be on the end of this list!! (period)
|
||||
};
|
||||
@@ -31,15 +31,15 @@ protected:
|
||||
* Send a STUN request to the STUN server letting the Game Coordinator know
|
||||
* what our actually public IP:port is.
|
||||
*
|
||||
* uint8 Game Coordinator protocol version.
|
||||
* uint8_t Game Coordinator protocol version.
|
||||
* string Token to track the current STUN request.
|
||||
* uint8 Which interface number this is (for example, IPv4 or IPv6).
|
||||
* uint8_t Which interface number this is (for example, IPv4 or IPv6).
|
||||
* The Game Coordinator relays this number back in later packets.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_SERCLI_STUN(Packet *p);
|
||||
virtual bool Receive_SERCLI_STUN(Packet &p);
|
||||
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../date_func.h"
|
||||
#include "../../timer/timer_game_calendar.h"
|
||||
#include "../../debug.h"
|
||||
#include "tcp_turn.h"
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
* @param p the packet to handle
|
||||
* @return true if we should immediately handle further packets, false otherwise
|
||||
*/
|
||||
bool NetworkTurnSocketHandler::HandlePacket(Packet *p)
|
||||
bool NetworkTurnSocketHandler::HandlePacket(Packet &p)
|
||||
{
|
||||
PacketTurnType type = (PacketTurnType)p->Recv_uint8();
|
||||
PacketTurnType type = (PacketTurnType)p.Recv_uint8();
|
||||
|
||||
switch (type) {
|
||||
case PACKET_TURN_TURN_ERROR: return this->Receive_TURN_ERROR(p);
|
||||
@@ -43,12 +43,11 @@ bool NetworkTurnSocketHandler::HandlePacket(Packet *p)
|
||||
*/
|
||||
bool NetworkTurnSocketHandler::ReceivePackets()
|
||||
{
|
||||
Packet *p;
|
||||
std::unique_ptr<Packet> p;
|
||||
static const int MAX_PACKETS_TO_RECEIVE = 4;
|
||||
int i = MAX_PACKETS_TO_RECEIVE;
|
||||
while (--i != 0 && (p = this->ReceivePacket()) != nullptr) {
|
||||
bool cont = this->HandlePacket(p);
|
||||
delete p;
|
||||
bool cont = this->HandlePacket(*p);
|
||||
if (!cont) return true;
|
||||
}
|
||||
|
||||
@@ -66,6 +65,6 @@ bool NetworkTurnSocketHandler::ReceiveInvalidPacket(PacketTurnType type)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkTurnSocketHandler::Receive_TURN_ERROR(Packet *p) { return this->ReceiveInvalidPacket(PACKET_TURN_TURN_ERROR); }
|
||||
bool NetworkTurnSocketHandler::Receive_SERCLI_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_TURN_SERCLI_CONNECT); }
|
||||
bool NetworkTurnSocketHandler::Receive_TURN_CONNECTED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_TURN_TURN_CONNECTED); }
|
||||
bool NetworkTurnSocketHandler::Receive_TURN_ERROR(Packet &) { return this->ReceiveInvalidPacket(PACKET_TURN_TURN_ERROR); }
|
||||
bool NetworkTurnSocketHandler::Receive_SERCLI_CONNECT(Packet &) { return this->ReceiveInvalidPacket(PACKET_TURN_SERCLI_CONNECT); }
|
||||
bool NetworkTurnSocketHandler::Receive_TURN_CONNECTED(Packet &) { return this->ReceiveInvalidPacket(PACKET_TURN_TURN_CONNECTED); }
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
#include "os_abstraction.h"
|
||||
#include "tcp.h"
|
||||
#include "packet.h"
|
||||
#include "game_info.h"
|
||||
#include "network_game_info.h"
|
||||
|
||||
/** Enum with all types of TCP TURN packets. The order MUST not be changed. **/
|
||||
enum PacketTurnType {
|
||||
enum PacketTurnType : uint8_t {
|
||||
PACKET_TURN_TURN_ERROR, ///< TURN server is unable to relay.
|
||||
PACKET_TURN_SERCLI_CONNECT, ///< Client or server is connecting to the TURN server.
|
||||
PACKET_TURN_TURN_CONNECTED, ///< TURN server indicates the socket is now being relayed.
|
||||
@@ -38,19 +38,19 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_TURN_ERROR(Packet *p);
|
||||
virtual bool Receive_TURN_ERROR(Packet &p);
|
||||
|
||||
/**
|
||||
* Client or servers wants to connect to the TURN server (on request by
|
||||
* the Game Coordinator).
|
||||
*
|
||||
* uint8 Game Coordinator protocol version.
|
||||
* uint8_t Game Coordinator protocol version.
|
||||
* string Token to track the current TURN request.
|
||||
*
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_SERCLI_CONNECT(Packet *p);
|
||||
virtual bool Receive_SERCLI_CONNECT(Packet &p);
|
||||
|
||||
/**
|
||||
* TURN server has connected client and server together and will now relay
|
||||
@@ -62,9 +62,9 @@ protected:
|
||||
* @param p The packet that was just received.
|
||||
* @return True upon success, otherwise false.
|
||||
*/
|
||||
virtual bool Receive_TURN_CONNECTED(Packet *p);
|
||||
virtual bool Receive_TURN_CONNECTED(Packet &p);
|
||||
|
||||
bool HandlePacket(Packet *p);
|
||||
bool HandlePacket(Packet &p);
|
||||
public:
|
||||
/**
|
||||
* Create a new cs socket handler for a given cs.
|
||||
|
||||
+22
-22
@@ -10,9 +10,9 @@
|
||||
*/
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../date_func.h"
|
||||
#include "../../timer/timer_game_calendar.h"
|
||||
#include "../../debug.h"
|
||||
#include "game_info.h"
|
||||
#include "network_game_info.h"
|
||||
#include "udp.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
@@ -50,7 +50,7 @@ bool NetworkUDPSocketHandler::Listen()
|
||||
addr.Listen(SOCK_DGRAM, &this->sockets);
|
||||
}
|
||||
|
||||
return this->sockets.size() != 0;
|
||||
return !this->sockets.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,7 +59,7 @@ bool NetworkUDPSocketHandler::Listen()
|
||||
void NetworkUDPSocketHandler::CloseSocket()
|
||||
{
|
||||
for (auto &s : this->sockets) {
|
||||
closesocket(s.second);
|
||||
closesocket(s.first);
|
||||
}
|
||||
this->sockets.clear();
|
||||
}
|
||||
@@ -71,30 +71,30 @@ void NetworkUDPSocketHandler::CloseSocket()
|
||||
* @param all send the packet using all sockets that can send it
|
||||
* @param broadcast whether to send a broadcast message
|
||||
*/
|
||||
void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool all, bool broadcast)
|
||||
void NetworkUDPSocketHandler::SendPacket(Packet &p, NetworkAddress &recv, bool all, bool broadcast)
|
||||
{
|
||||
if (this->sockets.size() == 0) this->Listen();
|
||||
if (this->sockets.empty()) this->Listen();
|
||||
|
||||
for (auto &s : this->sockets) {
|
||||
/* Make a local copy because if we resolve it we cannot
|
||||
* easily unresolve it so we can resolve it later again. */
|
||||
NetworkAddress send(*recv);
|
||||
NetworkAddress send(recv);
|
||||
|
||||
/* Not the same type */
|
||||
if (!send.IsFamily(s.first.GetAddress()->ss_family)) continue;
|
||||
if (!send.IsFamily(s.second.GetAddress()->ss_family)) continue;
|
||||
|
||||
p->PrepareToSend();
|
||||
p.PrepareToSend();
|
||||
|
||||
if (broadcast) {
|
||||
/* Enable broadcast */
|
||||
unsigned long val = 1;
|
||||
if (setsockopt(s.second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) {
|
||||
if (setsockopt(s.first, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) {
|
||||
Debug(net, 1, "Setting broadcast mode failed: {}", NetworkError::GetLast().AsString());
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the buffer */
|
||||
ssize_t res = p->TransferOut<int>(sendto, s.second, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength());
|
||||
ssize_t res = p.TransferOut<int>(sendto, s.first, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength());
|
||||
Debug(net, 7, "sendto({})", send.GetAddressAsString());
|
||||
|
||||
/* Check for any errors, but ignore it otherwise */
|
||||
@@ -119,8 +119,8 @@ void NetworkUDPSocketHandler::ReceivePackets()
|
||||
socklen_t client_len = sizeof(client_addr);
|
||||
|
||||
/* Try to receive anything */
|
||||
SetNonBlocking(s.second); // Some OSes seem to lose the non-blocking status of the socket
|
||||
ssize_t nbytes = p.TransferIn<int>(recvfrom, s.second, 0, (struct sockaddr *)&client_addr, &client_len);
|
||||
SetNonBlocking(s.first); // Some OSes seem to lose the non-blocking status of the socket
|
||||
ssize_t nbytes = p.TransferIn<int>(recvfrom, s.first, 0, (struct sockaddr *)&client_addr, &client_len);
|
||||
|
||||
/* Did we get the bytes for the base header of the packet? */
|
||||
if (nbytes <= 0) break; // No data, i.e. no packet
|
||||
@@ -137,7 +137,7 @@ void NetworkUDPSocketHandler::ReceivePackets()
|
||||
p.PrepareToRead();
|
||||
|
||||
/* Handle the packet */
|
||||
this->HandleUDPPacket(&p, &address);
|
||||
this->HandleUDPPacket(p, address);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,14 +147,14 @@ void NetworkUDPSocketHandler::ReceivePackets()
|
||||
* @param p the received packet
|
||||
* @param client_addr the sender of the packet
|
||||
*/
|
||||
void NetworkUDPSocketHandler::HandleUDPPacket(Packet *p, NetworkAddress *client_addr)
|
||||
void NetworkUDPSocketHandler::HandleUDPPacket(Packet &p, NetworkAddress &client_addr)
|
||||
{
|
||||
PacketUDPType type;
|
||||
|
||||
/* New packet == new client, which has not quit yet */
|
||||
this->Reopen();
|
||||
|
||||
type = (PacketUDPType)p->Recv_uint8();
|
||||
type = (PacketUDPType)p.Recv_uint8();
|
||||
|
||||
switch (this->HasClientQuit() ? PACKET_UDP_END : type) {
|
||||
case PACKET_UDP_CLIENT_FIND_SERVER: this->Receive_CLIENT_FIND_SERVER(p, client_addr); break;
|
||||
@@ -162,9 +162,9 @@ void NetworkUDPSocketHandler::HandleUDPPacket(Packet *p, NetworkAddress *client_
|
||||
|
||||
default:
|
||||
if (this->HasClientQuit()) {
|
||||
Debug(net, 0, "[udp] Received invalid packet type {} from {}", type, client_addr->GetAddressAsString());
|
||||
Debug(net, 0, "[udp] Received invalid packet type {} from {}", type, client_addr.GetAddressAsString());
|
||||
} else {
|
||||
Debug(net, 0, "[udp] Received illegal packet from {}", client_addr->GetAddressAsString());
|
||||
Debug(net, 0, "[udp] Received illegal packet from {}", client_addr.GetAddressAsString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -175,10 +175,10 @@ void NetworkUDPSocketHandler::HandleUDPPacket(Packet *p, NetworkAddress *client_
|
||||
* @param type The received packet type.
|
||||
* @param client_addr The address we received the packet from.
|
||||
*/
|
||||
void NetworkUDPSocketHandler::ReceiveInvalidPacket(PacketUDPType type, NetworkAddress *client_addr)
|
||||
void NetworkUDPSocketHandler::ReceiveInvalidPacket(PacketUDPType type, NetworkAddress &client_addr)
|
||||
{
|
||||
Debug(net, 0, "[udp] Received packet type {} on wrong port from {}", type, client_addr->GetAddressAsString());
|
||||
Debug(net, 0, "[udp] Received packet type {} on wrong port from {}", type, client_addr.GetAddressAsString());
|
||||
}
|
||||
|
||||
void NetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_FIND_SERVER, client_addr); }
|
||||
void NetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_RESPONSE, client_addr); }
|
||||
void NetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet &, NetworkAddress &client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_FIND_SERVER, client_addr); }
|
||||
void NetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet &, NetworkAddress &client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_RESPONSE, client_addr); }
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "packet.h"
|
||||
|
||||
/** Enum with all types of UDP packets. The order MUST not be changed **/
|
||||
enum PacketUDPType {
|
||||
enum PacketUDPType : uint8_t {
|
||||
PACKET_UDP_CLIENT_FIND_SERVER, ///< Queries a game server for game information
|
||||
PACKET_UDP_SERVER_RESPONSE, ///< Reply of the game server with game information
|
||||
PACKET_UDP_END, ///< Must ALWAYS be on the end of this list!! (period)
|
||||
@@ -30,23 +30,23 @@ protected:
|
||||
/** The opened sockets. */
|
||||
SocketList sockets;
|
||||
|
||||
void ReceiveInvalidPacket(PacketUDPType, NetworkAddress *client_addr);
|
||||
void ReceiveInvalidPacket(PacketUDPType, NetworkAddress &client_addr);
|
||||
|
||||
/**
|
||||
* Queries to the server for information about the game.
|
||||
* @param p The received packet.
|
||||
* @param client_addr The origin of the packet.
|
||||
*/
|
||||
virtual void Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr);
|
||||
virtual void Receive_CLIENT_FIND_SERVER(Packet &p, NetworkAddress &client_addr);
|
||||
|
||||
/**
|
||||
* Response to a query letting the client know we are here.
|
||||
* @param p The received packet.
|
||||
* @param client_addr The origin of the packet.
|
||||
*/
|
||||
virtual void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr);
|
||||
virtual void Receive_SERVER_RESPONSE(Packet &p, NetworkAddress &client_addr);
|
||||
|
||||
void HandleUDPPacket(Packet *p, NetworkAddress *client_addr);
|
||||
void HandleUDPPacket(Packet &p, NetworkAddress &client_addr);
|
||||
public:
|
||||
NetworkUDPSocketHandler(NetworkAddressList *bind = nullptr);
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
bool Listen();
|
||||
void CloseSocket();
|
||||
|
||||
void SendPacket(Packet *p, NetworkAddress *recv, bool all = false, bool broadcast = false);
|
||||
void SendPacket(Packet &p, NetworkAddress &recv, bool all = false, bool broadcast = false);
|
||||
void ReceivePackets();
|
||||
};
|
||||
|
||||
|
||||
+84
-104
@@ -11,7 +11,8 @@
|
||||
|
||||
#include "../strings_func.h"
|
||||
#include "../command_func.h"
|
||||
#include "../date_func.h"
|
||||
#include "../timer/timer_game_tick.h"
|
||||
#include "../timer/timer_game_economy.h"
|
||||
#include "network_admin.h"
|
||||
#include "network_client.h"
|
||||
#include "network_query.h"
|
||||
@@ -63,20 +64,20 @@ bool _is_network_server; ///< Does this client wants to be a network-server?
|
||||
NetworkCompanyState *_network_company_states = nullptr; ///< Statistics about some companies.
|
||||
ClientID _network_own_client_id; ///< Our client identifier.
|
||||
ClientID _redirect_console_to_client; ///< If not invalid, redirect the console output to a client.
|
||||
uint8 _network_reconnect; ///< Reconnect timeout
|
||||
uint8_t _network_reconnect; ///< Reconnect timeout
|
||||
StringList _network_bind_list; ///< The addresses to bind on.
|
||||
StringList _network_host_list; ///< The servers we know.
|
||||
StringList _network_ban_list; ///< The banned clients.
|
||||
uint32 _frame_counter_server; ///< The frame_counter of the server, if in network-mode
|
||||
uint32 _frame_counter_max; ///< To where we may go with our clients
|
||||
uint32 _frame_counter; ///< The current frame.
|
||||
uint32 _last_sync_frame; ///< Used in the server to store the last time a sync packet was sent to clients.
|
||||
uint32_t _frame_counter_server; ///< The frame_counter of the server, if in network-mode
|
||||
uint32_t _frame_counter_max; ///< To where we may go with our clients
|
||||
uint32_t _frame_counter; ///< The current frame.
|
||||
uint32_t _last_sync_frame; ///< Used in the server to store the last time a sync packet was sent to clients.
|
||||
NetworkAddressList _broadcast_list; ///< List of broadcast addresses.
|
||||
uint32 _sync_seed_1; ///< Seed to compare during sync checks.
|
||||
uint32_t _sync_seed_1; ///< Seed to compare during sync checks.
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
uint32 _sync_seed_2; ///< Second part of the seed.
|
||||
uint32_t _sync_seed_2; ///< Second part of the seed.
|
||||
#endif
|
||||
uint32 _sync_frame; ///< The frame to perform the sync check.
|
||||
uint32_t _sync_frame; ///< The frame to perform the sync check.
|
||||
bool _network_first_time; ///< Whether we have finished joining or not.
|
||||
CompanyMask _network_company_passworded; ///< Bitmask of the password status of all companies.
|
||||
|
||||
@@ -85,8 +86,7 @@ static_assert((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS
|
||||
/** The amount of clients connected */
|
||||
byte _network_clients_connected = 0;
|
||||
|
||||
/* Some externs / forwards */
|
||||
extern void StateGameLoop();
|
||||
extern std::string GenerateUid(std::string_view subject);
|
||||
|
||||
/**
|
||||
* Return whether there is any client connected or trying to connect at all.
|
||||
@@ -174,7 +174,7 @@ std::string NetworkChangeCompanyPassword(CompanyID company_id, std::string passw
|
||||
* @param password_game_seed Game seed.
|
||||
* @return The hashed password.
|
||||
*/
|
||||
std::string GenerateCompanyPasswordHash(const std::string &password, const std::string &password_server_id, uint32 password_game_seed)
|
||||
std::string GenerateCompanyPasswordHash(const std::string &password, const std::string &password_server_id, uint32_t password_game_seed)
|
||||
{
|
||||
if (password.empty()) return password;
|
||||
|
||||
@@ -191,18 +191,14 @@ std::string GenerateCompanyPasswordHash(const std::string &password, const std::
|
||||
}
|
||||
|
||||
Md5 checksum;
|
||||
uint8 digest[16];
|
||||
MD5Hash digest;
|
||||
|
||||
/* Generate the MD5 hash */
|
||||
std::string salted_password_string = salted_password.str();
|
||||
checksum.Append(salted_password_string.data(), salted_password_string.size());
|
||||
checksum.Finish(digest);
|
||||
|
||||
std::ostringstream hashed_password;
|
||||
hashed_password << std::hex << std::setfill('0');
|
||||
for (int di = 0; di < 16; di++) hashed_password << std::setw(2) << (int)digest[di]; // Cast needed, otherwise interpreted as character to add
|
||||
|
||||
return hashed_password.str();
|
||||
return FormatArrayAsHex(digest);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,7 +214,7 @@ bool NetworkCompanyIsPassworded(CompanyID company_id)
|
||||
/* This puts a text-message to the console, or in the future, the chat-box,
|
||||
* (to keep it all a bit more general)
|
||||
* If 'self_send' is true, this is the client who is sending the message */
|
||||
void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, const std::string &name, const std::string &str, int64 data, const std::string &data_str)
|
||||
void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, const std::string &name, const std::string &str, int64_t data, const std::string &data_str)
|
||||
{
|
||||
StringID strid;
|
||||
switch (action) {
|
||||
@@ -253,7 +249,6 @@ void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send,
|
||||
default: strid = STR_NETWORK_CHAT_ALL; break;
|
||||
}
|
||||
|
||||
char message[1024];
|
||||
SetDParamStr(0, name);
|
||||
SetDParamStr(1, str);
|
||||
SetDParam(2, data);
|
||||
@@ -263,10 +258,12 @@ void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send,
|
||||
* right-to-left characters depending on the context. As the next text might be an user's name, the
|
||||
* user name's characters will influence the direction of the "***" instead of the language setting
|
||||
* of the game. Manually set the direction of the "***" by inserting a text-direction marker. */
|
||||
char *msg_ptr = message + Utf8Encode(message, _current_text_dir == TD_LTR ? CHAR_TD_LRM : CHAR_TD_RLM);
|
||||
GetString(msg_ptr, strid, lastof(message));
|
||||
std::ostringstream stream;
|
||||
std::ostreambuf_iterator<char> iterator(stream);
|
||||
Utf8Encode(iterator, _current_text_dir == TD_LTR ? CHAR_TD_LRM : CHAR_TD_RLM);
|
||||
std::string message = stream.str() + GetString(strid);
|
||||
|
||||
Debug(desync, 1, "msg: {:08x}; {:02x}; {}", _date, _date_fract, message);
|
||||
Debug(desync, 1, "msg: {:08x}; {:02x}; {}", TimerGameEconomy::date, TimerGameEconomy::date_fract, message);
|
||||
IConsolePrint(colour, message);
|
||||
NetworkAddChatMessage(colour, _settings_client.gui.network_chat_timeout, message);
|
||||
}
|
||||
@@ -278,8 +275,8 @@ uint NetworkCalculateLag(const NetworkClientSocket *cs)
|
||||
/* This client has missed their ACK packet after 1 DAY_TICKS..
|
||||
* so we increase their lag for every frame that passes!
|
||||
* The packet can be out by a max of _net_frame_freq */
|
||||
if (cs->last_frame_server + DAY_TICKS + _settings_client.network.frame_freq < _frame_counter) {
|
||||
lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _settings_client.network.frame_freq);
|
||||
if (cs->last_frame_server + Ticks::DAY_TICKS + _settings_client.network.frame_freq < _frame_counter) {
|
||||
lag += _frame_counter - (cs->last_frame_server + Ticks::DAY_TICKS + _settings_client.network.frame_freq);
|
||||
}
|
||||
return lag;
|
||||
}
|
||||
@@ -470,7 +467,7 @@ std::string_view ParseCompanyFromConnectionString(const std::string &connection_
|
||||
std::string_view company_string = ip.substr(offset + 1);
|
||||
ip = ip.substr(0, offset);
|
||||
|
||||
uint8 company_value;
|
||||
uint8_t company_value;
|
||||
auto [_, err] = std::from_chars(company_string.data(), company_string.data() + company_string.size(), company_value);
|
||||
if (err == std::errc()) {
|
||||
if (company_value != COMPANY_NEW_COMPANY && company_value != COMPANY_SPECTATOR) {
|
||||
@@ -504,7 +501,7 @@ std::string_view ParseCompanyFromConnectionString(const std::string &connection_
|
||||
* @param company_id The company ID to set, if available.
|
||||
* @return A std::string_view into the connection string with the (IP) address part.
|
||||
*/
|
||||
std::string_view ParseFullConnectionString(const std::string &connection_string, uint16 &port, CompanyID *company_id)
|
||||
std::string_view ParseFullConnectionString(const std::string &connection_string, uint16_t &port, CompanyID *company_id)
|
||||
{
|
||||
std::string_view ip = ParseCompanyFromConnectionString(connection_string, company_id);
|
||||
|
||||
@@ -524,9 +521,9 @@ std::string_view ParseFullConnectionString(const std::string &connection_string,
|
||||
* @param default_port The port to use if none is given.
|
||||
* @return The normalized connection string.
|
||||
*/
|
||||
std::string NormalizeConnectionString(const std::string &connection_string, uint16 default_port)
|
||||
std::string NormalizeConnectionString(const std::string &connection_string, uint16_t default_port)
|
||||
{
|
||||
uint16 port = default_port;
|
||||
uint16_t port = default_port;
|
||||
std::string_view ip = ParseFullConnectionString(connection_string, port);
|
||||
return std::string(ip) + ":" + std::to_string(port);
|
||||
}
|
||||
@@ -539,9 +536,9 @@ std::string NormalizeConnectionString(const std::string &connection_string, uint
|
||||
* @param default_port The default port to set port to if not in connection_string.
|
||||
* @return A valid NetworkAddress of the parsed information.
|
||||
*/
|
||||
NetworkAddress ParseConnectionString(const std::string &connection_string, uint16 default_port)
|
||||
NetworkAddress ParseConnectionString(const std::string &connection_string, uint16_t default_port)
|
||||
{
|
||||
uint16 port = default_port;
|
||||
uint16_t port = default_port;
|
||||
std::string_view ip = ParseFullConnectionString(connection_string, port);
|
||||
return NetworkAddress(ip, port);
|
||||
}
|
||||
@@ -599,6 +596,7 @@ void NetworkClose(bool close_admins)
|
||||
|
||||
_network_coordinator_client.CloseAllConnections();
|
||||
}
|
||||
NetworkGameSocketHandler::ProcessDeferredDeletions();
|
||||
|
||||
TCPConnecter::KillAll();
|
||||
|
||||
@@ -626,7 +624,7 @@ static void NetworkInitialize(bool close_admins = true)
|
||||
}
|
||||
|
||||
/** Non blocking connection to query servers for their game info. */
|
||||
class TCPQueryConnecter : TCPServerConnecter {
|
||||
class TCPQueryConnecter : public TCPServerConnecter {
|
||||
private:
|
||||
std::string connection_string;
|
||||
|
||||
@@ -635,6 +633,8 @@ public:
|
||||
|
||||
void OnFailure() override
|
||||
{
|
||||
Debug(net, 9, "Query::OnFailure(): connection_string={}", this->connection_string);
|
||||
|
||||
NetworkGameList *item = NetworkGameListAddItem(connection_string);
|
||||
item->status = NGLS_OFFLINE;
|
||||
item->refreshing = false;
|
||||
@@ -644,6 +644,8 @@ public:
|
||||
|
||||
void OnConnect(SOCKET s) override
|
||||
{
|
||||
Debug(net, 9, "Query::OnConnect(): connection_string={}", this->connection_string);
|
||||
|
||||
QueryNetworkGameSocketHandler::QueryServer(s, this->connection_string);
|
||||
}
|
||||
};
|
||||
@@ -656,11 +658,13 @@ void NetworkQueryServer(const std::string &connection_string)
|
||||
{
|
||||
if (!_network_available) return;
|
||||
|
||||
Debug(net, 9, "NetworkQueryServer(): connection_string={}", connection_string);
|
||||
|
||||
/* Mark the entry as refreshing, so the GUI can show the refresh is pending. */
|
||||
NetworkGameList *item = NetworkGameListAddItem(connection_string);
|
||||
item->refreshing = true;
|
||||
|
||||
new TCPQueryConnecter(connection_string);
|
||||
TCPConnecter::Create<TCPQueryConnecter>(connection_string);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -698,14 +702,14 @@ NetworkGameList *NetworkAddServer(const std::string &connection_string, bool man
|
||||
* @param addresses the list to write to.
|
||||
* @param port the port to bind to.
|
||||
*/
|
||||
void GetBindAddresses(NetworkAddressList *addresses, uint16 port)
|
||||
void GetBindAddresses(NetworkAddressList *addresses, uint16_t port)
|
||||
{
|
||||
for (const auto &iter : _network_bind_list) {
|
||||
addresses->emplace_back(iter.c_str(), port);
|
||||
}
|
||||
|
||||
/* No address, so bind to everything. */
|
||||
if (addresses->size() == 0) {
|
||||
if (addresses->empty()) {
|
||||
addresses->emplace_back("", port);
|
||||
}
|
||||
}
|
||||
@@ -723,7 +727,7 @@ void NetworkRebuildHostList()
|
||||
}
|
||||
|
||||
/** Non blocking connection create to actually connect to servers */
|
||||
class TCPClientConnecter : TCPServerConnecter {
|
||||
class TCPClientConnecter : public TCPServerConnecter {
|
||||
private:
|
||||
std::string connection_string;
|
||||
|
||||
@@ -732,11 +736,15 @@ public:
|
||||
|
||||
void OnFailure() override
|
||||
{
|
||||
Debug(net, 9, "Client::OnFailure(): connection_string={}", this->connection_string);
|
||||
|
||||
ShowNetworkError(STR_NETWORK_ERROR_NOCONNECTION);
|
||||
}
|
||||
|
||||
void OnConnect(SOCKET s) override
|
||||
{
|
||||
Debug(net, 9, "Client::OnConnect(): connection_string={}", this->connection_string);
|
||||
|
||||
_networking = true;
|
||||
new ClientNetworkGameSocketHandler(s, this->connection_string);
|
||||
IConsoleCmdExec("exec scripts/on_client.scr 0");
|
||||
@@ -763,6 +771,8 @@ public:
|
||||
*/
|
||||
bool NetworkClientConnectGame(const std::string &connection_string, CompanyID default_company, const std::string &join_server_password, const std::string &join_company_password)
|
||||
{
|
||||
Debug(net, 9, "NetworkClientConnectGame(): connection_string={}", connection_string);
|
||||
|
||||
CompanyID join_as = default_company;
|
||||
std::string resolved_connection_string = ServerAddress::Parse(connection_string, NETWORK_DEFAULT_PORT, &join_as).connection_string;
|
||||
|
||||
@@ -799,10 +809,11 @@ void NetworkClientJoinGame()
|
||||
NetworkInitialize();
|
||||
|
||||
_settings_client.network.last_joined = _network_join.connection_string;
|
||||
Debug(net, 9, "status = CONNECTING");
|
||||
_network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
|
||||
ShowJoinStatusWindow();
|
||||
|
||||
new TCPClientConnecter(_network_join.connection_string);
|
||||
TCPConnecter::Create<TCPClientConnecter>(_network_join.connection_string);
|
||||
}
|
||||
|
||||
static void NetworkInitGameInfo()
|
||||
@@ -872,7 +883,7 @@ bool NetworkServerStart()
|
||||
/* Check for the client and server names to be set, but only after the scripts had a chance to set them.*/
|
||||
if (_network_dedicated) CheckClientAndServerName();
|
||||
|
||||
NetworkDisconnect(false, false);
|
||||
NetworkDisconnect(false);
|
||||
NetworkInitialize(false);
|
||||
NetworkUDPInitialize();
|
||||
Debug(net, 5, "Starting listeners for clients");
|
||||
@@ -940,10 +951,9 @@ void NetworkReboot()
|
||||
|
||||
/**
|
||||
* We want to disconnect from the host/clients.
|
||||
* @param blocking whether to wait till everything has been closed.
|
||||
* @param close_admins Whether the admin sockets need to be closed as well.
|
||||
*/
|
||||
void NetworkDisconnect(bool blocking, bool close_admins)
|
||||
void NetworkDisconnect(bool close_admins)
|
||||
{
|
||||
if (_network_server) {
|
||||
for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
|
||||
@@ -996,12 +1006,15 @@ void NetworkUpdateServerGameType()
|
||||
*/
|
||||
static bool NetworkReceive()
|
||||
{
|
||||
bool result;
|
||||
if (_network_server) {
|
||||
ServerNetworkAdminSocketHandler::Receive();
|
||||
return ServerNetworkGameSocketHandler::Receive();
|
||||
result = ServerNetworkGameSocketHandler::Receive();
|
||||
} else {
|
||||
return ClientNetworkGameSocketHandler::Receive();
|
||||
result = ClientNetworkGameSocketHandler::Receive();
|
||||
}
|
||||
NetworkGameSocketHandler::ProcessDeferredDeletions();
|
||||
return result;
|
||||
}
|
||||
|
||||
/* This sends all buffered commands (if possible) */
|
||||
@@ -1013,6 +1026,7 @@ static void NetworkSend()
|
||||
} else {
|
||||
ClientNetworkGameSocketHandler::Send();
|
||||
}
|
||||
NetworkGameSocketHandler::ProcessDeferredDeletions();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1027,6 +1041,7 @@ void NetworkBackgroundLoop()
|
||||
TCPConnecter::CheckCallbacks();
|
||||
NetworkHTTPSocketHandler::HTTPReceive();
|
||||
QueryNetworkGameSocketHandler::SendReceive();
|
||||
NetworkGameSocketHandler::ProcessDeferredDeletions();
|
||||
|
||||
NetworkBackgroundUDPLoop();
|
||||
}
|
||||
@@ -1041,42 +1056,42 @@ void NetworkGameLoop()
|
||||
|
||||
if (_network_server) {
|
||||
/* Log the sync state to check for in-syncedness of replays. */
|
||||
if (_date_fract == 0) {
|
||||
if (TimerGameEconomy::date_fract == 0) {
|
||||
/* We don't want to log multiple times if paused. */
|
||||
static Date last_log;
|
||||
if (last_log != _date) {
|
||||
Debug(desync, 1, "sync: {:08x}; {:02x}; {:08x}; {:08x}", _date, _date_fract, _random.state[0], _random.state[1]);
|
||||
last_log = _date;
|
||||
static TimerGameEconomy::Date last_log;
|
||||
if (last_log != TimerGameEconomy::date) {
|
||||
Debug(desync, 1, "sync: {:08x}; {:02x}; {:08x}; {:08x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, _random.state[0], _random.state[1]);
|
||||
last_log = TimerGameEconomy::date;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DUMP_COMMANDS
|
||||
/* Loading of the debug commands from -ddesync>=1 */
|
||||
static FILE *f = FioFOpenFile("commands.log", "rb", SAVE_DIR);
|
||||
static Date next_date = 0;
|
||||
static uint32 next_date_fract;
|
||||
static TimerGameEconomy::Date next_date(0);
|
||||
static uint32_t next_date_fract;
|
||||
static CommandPacket *cp = nullptr;
|
||||
static bool check_sync_state = false;
|
||||
static uint32 sync_state[2];
|
||||
static uint32_t sync_state[2];
|
||||
if (f == nullptr && next_date == 0) {
|
||||
Debug(desync, 0, "Cannot open commands.log");
|
||||
next_date = 1;
|
||||
next_date = TimerGameEconomy::Date(1);
|
||||
}
|
||||
|
||||
while (f != nullptr && !feof(f)) {
|
||||
if (_date == next_date && _date_fract == next_date_fract) {
|
||||
if (TimerGameEconomy::date == next_date && TimerGameEconomy::date_fract == next_date_fract) {
|
||||
if (cp != nullptr) {
|
||||
NetworkSendCommand(cp->cmd, cp->err_msg, nullptr, cp->company, cp->data);
|
||||
Debug(desync, 0, "Injecting: {:08x}; {:02x}; {:02x}; {:08x}; {:06x}; {} ({})", _date, _date_fract, (int)_current_company, cp->cmd, cp->tile, FormatArrayAsHex(cp->data), GetCommandName(cp->cmd));
|
||||
Debug(desync, 0, "Injecting: {:08x}; {:02x}; {:02x}; {:08x}; {} ({})", TimerGameEconomy::date, TimerGameEconomy::date_fract, (int)_current_company, cp->cmd, FormatArrayAsHex(cp->data), GetCommandName(cp->cmd));
|
||||
delete cp;
|
||||
cp = nullptr;
|
||||
}
|
||||
if (check_sync_state) {
|
||||
if (sync_state[0] == _random.state[0] && sync_state[1] == _random.state[1]) {
|
||||
Debug(desync, 0, "Sync check: {:08x}; {:02x}; match", _date, _date_fract);
|
||||
Debug(desync, 0, "Sync check: {:08x}; {:02x}; match", TimerGameEconomy::date, TimerGameEconomy::date_fract);
|
||||
} else {
|
||||
Debug(desync, 0, "Sync check: {:08x}; {:02x}; mismatch expected {{{:08x}, {:08x}}}, got {{{:08x}, {:08x}}}",
|
||||
_date, _date_fract, sync_state[0], sync_state[1], _random.state[0], _random.state[1]);
|
||||
TimerGameEconomy::date, TimerGameEconomy::date_fract, sync_state[0], sync_state[1], _random.state[0], _random.state[1]);
|
||||
NOT_REACHED();
|
||||
}
|
||||
check_sync_state = false;
|
||||
@@ -1107,8 +1122,10 @@ void NetworkGameLoop()
|
||||
int company;
|
||||
uint cmd;
|
||||
char buffer[256];
|
||||
int ret = sscanf(p, "%x; %x; %x; %x; %x; %x; %255s", &next_date, &next_date_fract, &company, &cmd, &cp->err_msg, &cp->tile, buffer);
|
||||
uint32_t next_date_raw;
|
||||
int ret = sscanf(p, "%x; %x; %x; %x; %x; %255s", &next_date_raw, &next_date_fract, &company, &cmd, &cp->err_msg, buffer);
|
||||
assert(ret == 6);
|
||||
next_date = TimerGameEconomy::Date((int32_t)next_date_raw);
|
||||
cp->company = (CompanyID)company;
|
||||
cp->cmd = (Commands)cmd;
|
||||
|
||||
@@ -1117,13 +1134,15 @@ void NetworkGameLoop()
|
||||
size_t arg_len = strlen(buffer);
|
||||
for (size_t i = 0; i + 1 < arg_len; i += 2) {
|
||||
byte e = 0;
|
||||
std::from_chars(buffer + i, buffer + i + 1, e, 16);
|
||||
std::from_chars(buffer + i, buffer + i + 2, e, 16);
|
||||
args.emplace_back(e);
|
||||
}
|
||||
cp->data = args;
|
||||
} else if (strncmp(p, "join: ", 6) == 0) {
|
||||
/* Manually insert a pause when joining; this way the client can join at the exact right time. */
|
||||
int ret = sscanf(p + 6, "%x; %x", &next_date, &next_date_fract);
|
||||
uint32_t next_date_raw;
|
||||
int ret = sscanf(p + 6, "%x; %x", &next_date_raw, &next_date_fract);
|
||||
next_date = TimerGameEconomy::Date((int32_t)next_date_raw);
|
||||
assert(ret == 2);
|
||||
Debug(desync, 0, "Injecting pause for join at {:08x}:{:02x}; please join when paused", next_date, next_date_fract);
|
||||
cp = new CommandPacket();
|
||||
@@ -1132,7 +1151,9 @@ void NetworkGameLoop()
|
||||
cp->data = EndianBufferWriter<>::FromValue(CommandTraits<CMD_PAUSE>::Args{ PM_PAUSED_NORMAL, true });
|
||||
_ddc_fastforward = false;
|
||||
} else if (strncmp(p, "sync: ", 6) == 0) {
|
||||
int ret = sscanf(p + 6, "%x; %x; %x; %x", &next_date, &next_date_fract, &sync_state[0], &sync_state[1]);
|
||||
uint32_t next_date_raw;
|
||||
int ret = sscanf(p + 6, "%x; %x; %x; %x", &next_date_raw, &next_date_fract, &sync_state[0], &sync_state[1]);
|
||||
next_date = TimerGameEconomy::Date((int32_t)next_date_raw);
|
||||
assert(ret == 4);
|
||||
check_sync_state = true;
|
||||
} else if (strncmp(p, "msg: ", 5) == 0 || strncmp(p, "client: ", 8) == 0 ||
|
||||
@@ -1207,50 +1228,7 @@ void NetworkGameLoop()
|
||||
|
||||
static void NetworkGenerateServerId()
|
||||
{
|
||||
Md5 checksum;
|
||||
uint8 digest[16];
|
||||
char hex_output[16 * 2 + 1];
|
||||
char coding_string[NETWORK_NAME_LENGTH];
|
||||
int di;
|
||||
|
||||
seprintf(coding_string, lastof(coding_string), "%d%s", (uint)Random(), "OpenTTD Server ID");
|
||||
|
||||
/* Generate the MD5 hash */
|
||||
checksum.Append((const uint8*)coding_string, strlen(coding_string));
|
||||
checksum.Finish(digest);
|
||||
|
||||
for (di = 0; di < 16; ++di) {
|
||||
seprintf(hex_output + di * 2, lastof(hex_output), "%02x", digest[di]);
|
||||
}
|
||||
|
||||
/* _settings_client.network.network_id is our id */
|
||||
_settings_client.network.network_id = hex_output;
|
||||
}
|
||||
|
||||
class TCPNetworkDebugConnecter : TCPConnecter {
|
||||
private:
|
||||
std::string connection_string;
|
||||
|
||||
public:
|
||||
TCPNetworkDebugConnecter(const std::string &connection_string) : TCPConnecter(connection_string, NETWORK_DEFAULT_DEBUGLOG_PORT), connection_string(connection_string) {}
|
||||
|
||||
void OnFailure() override
|
||||
{
|
||||
Debug(net, 0, "Failed to open connection to {} for redirecting Debug()", this->connection_string);
|
||||
}
|
||||
|
||||
void OnConnect(SOCKET s) override
|
||||
{
|
||||
Debug(net, 3, "Redirecting Debug() to {}", this->connection_string);
|
||||
|
||||
extern SOCKET _debug_socket;
|
||||
_debug_socket = s;
|
||||
}
|
||||
};
|
||||
|
||||
void NetworkStartDebugLog(const std::string &connection_string)
|
||||
{
|
||||
new TCPNetworkDebugConnecter(connection_string);
|
||||
_settings_client.network.network_id = GenerateUid("OpenTTD Server ID");
|
||||
}
|
||||
|
||||
/** This tries to launch the network for a given OS */
|
||||
@@ -1271,12 +1249,14 @@ void NetworkStartUp()
|
||||
NetworkUDPInitialize();
|
||||
Debug(net, 3, "Network online, multiplayer available");
|
||||
NetworkFindBroadcastIPs(&_broadcast_list);
|
||||
NetworkHTTPInitialize();
|
||||
}
|
||||
|
||||
/** This shuts the network down */
|
||||
void NetworkShutDown()
|
||||
{
|
||||
NetworkDisconnect(true);
|
||||
NetworkDisconnect();
|
||||
NetworkHTTPUninitialize();
|
||||
NetworkUDPClose();
|
||||
|
||||
Debug(net, 3, "Shutting down network");
|
||||
|
||||
+108
-126
@@ -9,8 +9,9 @@
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../strings_func.h"
|
||||
#include "../date_func.h"
|
||||
#include "core/game_info.h"
|
||||
#include "../timer/timer_game_calendar.h"
|
||||
#include "../timer/timer_game_calendar.h"
|
||||
#include "core/network_game_info.h"
|
||||
#include "network_admin.h"
|
||||
#include "network_base.h"
|
||||
#include "network_server.h"
|
||||
@@ -133,10 +134,10 @@ ServerNetworkAdminSocketHandler::~ServerNetworkAdminSocketHandler()
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendError(NetworkErrorCode error)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_ERROR);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_ERROR);
|
||||
|
||||
p->Send_uint8(error);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
std::string error_message = GetString(GetNetworkErrorMsg(error));
|
||||
|
||||
@@ -148,7 +149,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendError(NetworkErrorCode er
|
||||
/** Send the protocol version to the admin. */
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendProtocol()
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_PROTOCOL);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_PROTOCOL);
|
||||
|
||||
/* announce the protocol version */
|
||||
p->Send_uint8(NETWORK_GAME_ADMIN_VERSION);
|
||||
@@ -160,7 +161,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendProtocol()
|
||||
}
|
||||
|
||||
p->Send_bool(false);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return this->SendWelcome();
|
||||
}
|
||||
@@ -168,7 +169,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendProtocol()
|
||||
/** Send a welcome message to the admin. */
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome()
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_WELCOME);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_WELCOME);
|
||||
|
||||
p->Send_string(_settings_client.network.server_name);
|
||||
p->Send_string(GetNetworkRevisionString());
|
||||
@@ -177,11 +178,11 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome()
|
||||
p->Send_string(""); // Used to be map-name.
|
||||
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
||||
p->Send_uint8 (_settings_game.game_creation.landscape);
|
||||
p->Send_uint32(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1));
|
||||
p->Send_uint16(MapSizeX());
|
||||
p->Send_uint16(MapSizeY());
|
||||
p->Send_uint32(TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1).base());
|
||||
p->Send_uint16(Map::SizeX());
|
||||
p->Send_uint16(Map::SizeY());
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -189,26 +190,26 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome()
|
||||
/** Tell the admin we started a new game. */
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendNewGame()
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_NEWGAME);
|
||||
this->SendPacket(p);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_NEWGAME);
|
||||
this->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Tell the admin we're shutting down. */
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendShutdown()
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_SHUTDOWN);
|
||||
this->SendPacket(p);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_SHUTDOWN);
|
||||
this->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Tell the admin the date. */
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendDate()
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_DATE);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_DATE);
|
||||
|
||||
p->Send_uint32(_date);
|
||||
this->SendPacket(p);
|
||||
p->Send_uint32(TimerGameCalendar::date.base());
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -219,10 +220,10 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendDate()
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientJoin(ClientID client_id)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_JOIN);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CLIENT_JOIN);
|
||||
|
||||
p->Send_uint32(client_id);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -237,16 +238,16 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkC
|
||||
/* Only send data when we're a proper client, not just someone trying to query the server. */
|
||||
if (ci == nullptr) return NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_INFO);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CLIENT_INFO);
|
||||
|
||||
p->Send_uint32(ci->client_id);
|
||||
p->Send_string(cs == nullptr ? "" : const_cast<NetworkAddress &>(cs->client_address).GetHostname());
|
||||
p->Send_string(ci->client_name);
|
||||
p->Send_uint8 (0); // Used to be language
|
||||
p->Send_uint32(ci->join_date);
|
||||
p->Send_uint32(ci->join_date.base());
|
||||
p->Send_uint8 (ci->client_playas);
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -258,13 +259,13 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkC
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientUpdate(const NetworkClientInfo *ci)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_UPDATE);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CLIENT_UPDATE);
|
||||
|
||||
p->Send_uint32(ci->client_id);
|
||||
p->Send_string(ci->client_name);
|
||||
p->Send_uint8 (ci->client_playas);
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -275,10 +276,10 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientUpdate(const Networ
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientQuit(ClientID client_id)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_QUIT);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CLIENT_QUIT);
|
||||
|
||||
p->Send_uint32(client_id);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -290,11 +291,11 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientQuit(ClientID clien
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientError(ClientID client_id, NetworkErrorCode error)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_ERROR);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CLIENT_ERROR);
|
||||
|
||||
p->Send_uint32(client_id);
|
||||
p->Send_uint8 (error);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -305,10 +306,10 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientError(ClientID clie
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyNew(CompanyID company_id)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_NEW);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_NEW);
|
||||
p->Send_uint8(company_id);
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -319,7 +320,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyNew(CompanyID comp
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company *c)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_INFO);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_INFO);
|
||||
|
||||
p->Send_uint8 (c->index);
|
||||
SetDParam(0, c->index);
|
||||
@@ -328,15 +329,11 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company
|
||||
p->Send_string(GetString(STR_PRESIDENT_NAME));
|
||||
p->Send_uint8 (c->colour);
|
||||
p->Send_bool (NetworkCompanyIsPassworded(c->index));
|
||||
p->Send_uint32(c->inaugurated_year);
|
||||
p->Send_uint32(c->inaugurated_year.base());
|
||||
p->Send_bool (c->is_ai);
|
||||
p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy
|
||||
|
||||
for (auto owner : c->share_owners) {
|
||||
p->Send_uint8(owner);
|
||||
}
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -348,7 +345,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Company *c)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_UPDATE);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_UPDATE);
|
||||
|
||||
p->Send_uint8 (c->index);
|
||||
SetDParam(0, c->index);
|
||||
@@ -359,11 +356,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Compa
|
||||
p->Send_bool (NetworkCompanyIsPassworded(c->index));
|
||||
p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy
|
||||
|
||||
for (auto owner : c->share_owners) {
|
||||
p->Send_uint8(owner);
|
||||
}
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -375,12 +368,12 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Compa
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason acrr)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_REMOVE);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_REMOVE);
|
||||
|
||||
p->Send_uint8(company_id);
|
||||
p->Send_uint8(acrr);
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -390,12 +383,9 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyEconomy()
|
||||
{
|
||||
for (const Company *company : Company::Iterate()) {
|
||||
/* Get the income. */
|
||||
Money income = 0;
|
||||
for (uint i = 0; i < lengthof(company->yearly_expenses[0]); i++) {
|
||||
income -= company->yearly_expenses[0][i];
|
||||
}
|
||||
Money income = -std::reduce(std::begin(company->yearly_expenses[0]), std::end(company->yearly_expenses[0]));
|
||||
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_ECONOMY);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_ECONOMY);
|
||||
|
||||
p->Send_uint8(company->index);
|
||||
|
||||
@@ -403,16 +393,16 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyEconomy()
|
||||
p->Send_uint64(company->money);
|
||||
p->Send_uint64(company->current_loan);
|
||||
p->Send_uint64(income);
|
||||
p->Send_uint16(static_cast<uint16>(std::min<uint64>(UINT16_MAX, company->cur_economy.delivered_cargo.GetSum<OverflowSafeInt64>())));
|
||||
p->Send_uint16(static_cast<uint16_t>(std::min<uint64_t>(UINT16_MAX, company->cur_economy.delivered_cargo.GetSum<OverflowSafeInt64>())));
|
||||
|
||||
/* Send stats for the last 2 quarters. */
|
||||
for (uint i = 0; i < 2; i++) {
|
||||
p->Send_uint64(company->old_economy[i].company_value);
|
||||
p->Send_uint16(company->old_economy[i].performance_history);
|
||||
p->Send_uint16(static_cast<uint16>(std::min<uint64>(UINT16_MAX, company->old_economy[i].delivered_cargo.GetSum<OverflowSafeInt64>())));
|
||||
p->Send_uint16(static_cast<uint16_t>(std::min<uint64_t>(UINT16_MAX, company->old_economy[i].delivered_cargo.GetSum<OverflowSafeInt64>())));
|
||||
}
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
}
|
||||
|
||||
|
||||
@@ -428,7 +418,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyStats()
|
||||
|
||||
/* Go through all the companies. */
|
||||
for (const Company *company : Company::Iterate()) {
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_STATS);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_STATS);
|
||||
|
||||
/* Send the information. */
|
||||
p->Send_uint8(company->index);
|
||||
@@ -441,7 +431,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyStats()
|
||||
p->Send_uint16(company_stats[company->index].num_station[i]);
|
||||
}
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
}
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
@@ -455,9 +445,9 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyStats()
|
||||
* @param msg The actual message.
|
||||
* @param data Arbitrary extra data.
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, int64 data)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, int64_t data)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_CHAT);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CHAT);
|
||||
|
||||
p->Send_uint8 (action);
|
||||
p->Send_uint8 (desttype);
|
||||
@@ -465,7 +455,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendChat(NetworkAction action
|
||||
p->Send_string(msg);
|
||||
p->Send_uint64(data);
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
@@ -475,10 +465,10 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendChat(NetworkAction action
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRconEnd(const std::string_view command)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_RCON_END);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_RCON_END);
|
||||
|
||||
p->Send_string(command);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -488,36 +478,36 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRconEnd(const std::string
|
||||
* @param colour The colour of the text.
|
||||
* @param result The result of the command.
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRcon(uint16 colour, const std::string_view result)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRcon(uint16_t colour, const std::string_view result)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_RCON);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_RCON);
|
||||
|
||||
p->Send_uint16(colour);
|
||||
p->Send_string(result);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_RCON(Packet *p)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_RCON(Packet &p)
|
||||
{
|
||||
if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
|
||||
std::string command = p->Recv_string(NETWORK_RCONCOMMAND_LENGTH);
|
||||
std::string command = p.Recv_string(NETWORK_RCONCOMMAND_LENGTH);
|
||||
|
||||
Debug(net, 3, "[admin] Rcon command from '{}' ({}): {}", this->admin_name, this->admin_version, command);
|
||||
|
||||
_redirect_console_to_admin = this->index;
|
||||
IConsoleCmdExec(command.c_str());
|
||||
IConsoleCmdExec(command);
|
||||
_redirect_console_to_admin = INVALID_ADMIN_ID;
|
||||
return this->SendRconEnd(command);
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Packet *p)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Packet &p)
|
||||
{
|
||||
if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
|
||||
std::string json = p->Recv_string(NETWORK_GAMESCRIPT_JSON_LENGTH);
|
||||
std::string json = p.Recv_string(NETWORK_GAMESCRIPT_JSON_LENGTH);
|
||||
|
||||
Debug(net, 6, "[admin] GameScript JSON from '{}' ({}): {}", this->admin_name, this->admin_version, json);
|
||||
|
||||
@@ -525,11 +515,11 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Pack
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_PING(Packet *p)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_PING(Packet &p)
|
||||
{
|
||||
if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
|
||||
uint32 d1 = p->Recv_uint32();
|
||||
uint32_t d1 = p.Recv_uint32();
|
||||
|
||||
Debug(net, 6, "[admin] Ping from '{}' ({}): {}", this->admin_name, this->admin_version, d1);
|
||||
|
||||
@@ -549,11 +539,11 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendConsole(const std::string
|
||||
* smaller than COMPAT_MTU. */
|
||||
if (origin.size() + string.size() + 2 + 3 >= COMPAT_MTU) return NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_CONSOLE);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CONSOLE);
|
||||
|
||||
p->Send_string(origin);
|
||||
p->Send_string(string);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -564,26 +554,21 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendConsole(const std::string
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendGameScript(const std::string_view json)
|
||||
{
|
||||
/* At the moment we cannot transmit anything larger than MTU. So we limit
|
||||
* the maximum amount of json data that can be sent. Account also for
|
||||
* the trailing \0 of the string */
|
||||
if (json.size() + 1 >= NETWORK_GAMESCRIPT_JSON_LENGTH) return NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_GAMESCRIPT);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_GAMESCRIPT);
|
||||
|
||||
p->Send_string(json);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Send ping-reply (pong) to admin **/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendPong(uint32 d1)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendPong(uint32_t d1)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_PONG);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_PONG);
|
||||
|
||||
p->Send_uint32(d1);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -591,19 +576,19 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendPong(uint32 d1)
|
||||
/** Send the names of the commands. */
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdNames()
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_CMD_NAMES);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CMD_NAMES);
|
||||
|
||||
for (uint16 i = 0; i < CMD_END; i++) {
|
||||
for (uint16_t i = 0; i < CMD_END; i++) {
|
||||
const char *cmdname = GetCommandName(static_cast<Commands>(i));
|
||||
|
||||
/* Should COMPAT_MTU be exceeded, start a new packet
|
||||
* (magic 5: 1 bool "more data" and one uint16 "command id", one
|
||||
* (magic 5: 1 bool "more data" and one uint16_t "command id", one
|
||||
* byte for string '\0' termination and 1 bool "no more data" */
|
||||
if (!p->CanWriteToPacket(strlen(cmdname) + 5)) {
|
||||
p->Send_bool(false);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
p = new Packet(ADMIN_PACKET_SERVER_CMD_NAMES);
|
||||
p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CMD_NAMES);
|
||||
}
|
||||
|
||||
p->Send_bool(true);
|
||||
@@ -613,7 +598,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdNames()
|
||||
|
||||
/* Marker to notify the end of the packet has been reached. */
|
||||
p->Send_bool(false);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -623,17 +608,17 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdNames()
|
||||
* @param client_id The client executing the command.
|
||||
* @param cp The command that would be executed.
|
||||
*/
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdLogging(ClientID client_id, const CommandPacket *cp)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdLogging(ClientID client_id, const CommandPacket &cp)
|
||||
{
|
||||
Packet *p = new Packet(ADMIN_PACKET_SERVER_CMD_LOGGING);
|
||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CMD_LOGGING);
|
||||
|
||||
p->Send_uint32(client_id);
|
||||
p->Send_uint8 (cp->company);
|
||||
p->Send_uint16(cp->cmd);
|
||||
p->Send_buffer(cp->data);
|
||||
p->Send_uint32(cp->frame);
|
||||
p->Send_uint8 (cp.company);
|
||||
p->Send_uint16(cp.cmd);
|
||||
p->Send_buffer(cp.data);
|
||||
p->Send_uint32(cp.frame);
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -642,11 +627,11 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdLogging(ClientID clien
|
||||
* Receiving functions
|
||||
************/
|
||||
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_JOIN(Packet *p)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_JOIN(Packet &p)
|
||||
{
|
||||
if (this->status != ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
|
||||
std::string password = p->Recv_string(NETWORK_PASSWORD_LENGTH);
|
||||
std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
|
||||
|
||||
if (_settings_client.network.admin_password.empty() ||
|
||||
_settings_client.network.admin_password.compare(password) != 0) {
|
||||
@@ -654,8 +639,8 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_JOIN(Packet *p)
|
||||
return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
|
||||
}
|
||||
|
||||
this->admin_name = p->Recv_string(NETWORK_CLIENT_NAME_LENGTH);
|
||||
this->admin_version = p->Recv_string(NETWORK_REVISION_LENGTH);
|
||||
this->admin_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
|
||||
this->admin_version = p.Recv_string(NETWORK_REVISION_LENGTH);
|
||||
|
||||
if (this->admin_name.empty() || this->admin_version.empty()) {
|
||||
/* no name or version supplied */
|
||||
@@ -669,18 +654,18 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_JOIN(Packet *p)
|
||||
return this->SendProtocol();
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_QUIT(Packet *p)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_QUIT(Packet &)
|
||||
{
|
||||
/* The admin is leaving nothing else to do */
|
||||
return this->CloseConnection();
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_UPDATE_FREQUENCY(Packet *p)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_UPDATE_FREQUENCY(Packet &p)
|
||||
{
|
||||
if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
|
||||
AdminUpdateType type = (AdminUpdateType)p->Recv_uint16();
|
||||
AdminUpdateFrequency freq = (AdminUpdateFrequency)p->Recv_uint16();
|
||||
AdminUpdateType type = (AdminUpdateType)p.Recv_uint16();
|
||||
AdminUpdateFrequency freq = (AdminUpdateFrequency)p.Recv_uint16();
|
||||
|
||||
if (type >= ADMIN_UPDATE_END || (_admin_update_type_frequencies[type] & freq) != freq) {
|
||||
/* The server does not know of this UpdateType. */
|
||||
@@ -695,12 +680,12 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_UPDATE_FREQUENC
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet *p)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet &p)
|
||||
{
|
||||
if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
|
||||
AdminUpdateType type = (AdminUpdateType)p->Recv_uint8();
|
||||
uint32 d1 = p->Recv_uint32();
|
||||
AdminUpdateType type = (AdminUpdateType)p.Recv_uint8();
|
||||
uint32_t d1 = p.Recv_uint32();
|
||||
|
||||
switch (type) {
|
||||
case ADMIN_UPDATE_DATE:
|
||||
@@ -761,15 +746,15 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet *p)
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_CHAT(Packet *p)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_CHAT(Packet &p)
|
||||
{
|
||||
if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
|
||||
NetworkAction action = (NetworkAction)p->Recv_uint8();
|
||||
DestType desttype = (DestType)p->Recv_uint8();
|
||||
int dest = p->Recv_uint32();
|
||||
NetworkAction action = (NetworkAction)p.Recv_uint8();
|
||||
DestType desttype = (DestType)p.Recv_uint8();
|
||||
int dest = p.Recv_uint32();
|
||||
|
||||
std::string msg = p->Recv_string(NETWORK_CHAT_LENGTH);
|
||||
std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
|
||||
|
||||
switch (action) {
|
||||
case NETWORK_ACTION_CHAT:
|
||||
@@ -787,17 +772,17 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_CHAT(Packet *p)
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_EXTERNAL_CHAT(Packet *p)
|
||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_EXTERNAL_CHAT(Packet &p)
|
||||
{
|
||||
if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
|
||||
std::string source = p->Recv_string(NETWORK_CHAT_LENGTH);
|
||||
TextColour colour = (TextColour)p->Recv_uint16();
|
||||
std::string user = p->Recv_string(NETWORK_CHAT_LENGTH);
|
||||
std::string msg = p->Recv_string(NETWORK_CHAT_LENGTH);
|
||||
std::string source = p.Recv_string(NETWORK_CHAT_LENGTH);
|
||||
TextColour colour = (TextColour)p.Recv_uint16();
|
||||
std::string user = p.Recv_string(NETWORK_CHAT_LENGTH);
|
||||
std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
|
||||
|
||||
if (!IsValidConsoleColour(colour)) {
|
||||
Debug(net, 1, "[admin] Not supported chat colour {} ({}, {}, {}) from '{}' ({}).", (uint16)colour, source, user, msg, this->admin_name, this->admin_version);
|
||||
Debug(net, 1, "[admin] Not supported chat colour {} ({}, {}, {}) from '{}' ({}).", (uint16_t)colour, source, user, msg, this->admin_name, this->admin_version);
|
||||
return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET);
|
||||
}
|
||||
|
||||
@@ -868,11 +853,10 @@ void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code)
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the admin network of company details.
|
||||
* Notify the admin network of a new company.
|
||||
* @param company the company of which details will be sent into the admin network.
|
||||
* @param new_company whether this is a new company or not.
|
||||
*/
|
||||
void NetworkAdminCompanyInfo(const Company *company, bool new_company)
|
||||
void NetworkAdminCompanyNew(const Company *company)
|
||||
{
|
||||
if (company == nullptr) {
|
||||
Debug(net, 1, "[admin] Empty company given for update");
|
||||
@@ -882,10 +866,8 @@ void NetworkAdminCompanyInfo(const Company *company, bool new_company)
|
||||
for (ServerNetworkAdminSocketHandler *as : ServerNetworkAdminSocketHandler::IterateActive()) {
|
||||
if (as->update_frequency[ADMIN_UPDATE_COMPANY_INFO] != ADMIN_FREQUENCY_AUTOMATIC) continue;
|
||||
|
||||
as->SendCompanyNew(company->index);
|
||||
as->SendCompanyInfo(company);
|
||||
if (new_company) {
|
||||
as->SendCompanyNew(company->index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -920,7 +902,7 @@ void NetworkAdminCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason bc
|
||||
/**
|
||||
* Send chat to the admin network (if they did opt in for the respective update).
|
||||
*/
|
||||
void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, int64 data, bool from_admin)
|
||||
void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, int64_t data, bool from_admin)
|
||||
{
|
||||
if (from_admin) return;
|
||||
|
||||
@@ -974,7 +956,7 @@ void NetworkAdminGameScript(const std::string_view json)
|
||||
* @param owner The owner of the CommandPacket (who sent us the CommandPacket).
|
||||
* @param cp The CommandPacket to be distributed.
|
||||
*/
|
||||
void NetworkAdminCmdLogging(const NetworkClientSocket *owner, const CommandPacket *cp)
|
||||
void NetworkAdminCmdLogging(const NetworkClientSocket *owner, const CommandPacket &cp)
|
||||
{
|
||||
ClientID client_id = owner == nullptr ? _network_own_client_id : owner->client_id;
|
||||
|
||||
|
||||
+16
-16
@@ -24,18 +24,18 @@ extern NetworkAdminSocketPool _networkadminsocket_pool;
|
||||
/** Class for handling the server side of the game connection. */
|
||||
class ServerNetworkAdminSocketHandler : public NetworkAdminSocketPool::PoolItem<&_networkadminsocket_pool>, public NetworkAdminSocketHandler, public TCPListenHandler<ServerNetworkAdminSocketHandler, ADMIN_PACKET_SERVER_FULL, ADMIN_PACKET_SERVER_BANNED> {
|
||||
protected:
|
||||
NetworkRecvStatus Receive_ADMIN_JOIN(Packet *p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_QUIT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_UPDATE_FREQUENCY(Packet *p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_POLL(Packet *p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_CHAT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_EXTERNAL_CHAT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_RCON(Packet *p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_GAMESCRIPT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_PING(Packet *p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_JOIN(Packet &p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_QUIT(Packet &p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_UPDATE_FREQUENCY(Packet &p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_POLL(Packet &p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_CHAT(Packet &p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_EXTERNAL_CHAT(Packet &p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_RCON(Packet &p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_GAMESCRIPT(Packet &p) override;
|
||||
NetworkRecvStatus Receive_ADMIN_PING(Packet &p) override;
|
||||
|
||||
NetworkRecvStatus SendProtocol();
|
||||
NetworkRecvStatus SendPong(uint32 d1);
|
||||
NetworkRecvStatus SendPong(uint32_t d1);
|
||||
public:
|
||||
AdminUpdateFrequency update_frequency[ADMIN_UPDATE_END]; ///< Admin requested update intervals.
|
||||
std::chrono::steady_clock::time_point connect_time; ///< Time of connection.
|
||||
@@ -62,12 +62,12 @@ public:
|
||||
NetworkRecvStatus SendCompanyEconomy();
|
||||
NetworkRecvStatus SendCompanyStats();
|
||||
|
||||
NetworkRecvStatus SendChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, int64 data);
|
||||
NetworkRecvStatus SendRcon(uint16 colour, const std::string_view command);
|
||||
NetworkRecvStatus SendChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, int64_t data);
|
||||
NetworkRecvStatus SendRcon(uint16_t colour, const std::string_view command);
|
||||
NetworkRecvStatus SendConsole(const std::string_view origin, const std::string_view command);
|
||||
NetworkRecvStatus SendGameScript(const std::string_view json);
|
||||
NetworkRecvStatus SendCmdNames();
|
||||
NetworkRecvStatus SendCmdLogging(ClientID client_id, const CommandPacket *cp);
|
||||
NetworkRecvStatus SendCmdLogging(ClientID client_id, const CommandPacket &cp);
|
||||
NetworkRecvStatus SendRconEnd(const std::string_view command);
|
||||
|
||||
static void Send();
|
||||
@@ -103,15 +103,15 @@ void NetworkAdminClientInfo(const NetworkClientSocket *cs, bool new_client = fal
|
||||
void NetworkAdminClientUpdate(const NetworkClientInfo *ci);
|
||||
void NetworkAdminClientQuit(ClientID client_id);
|
||||
void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code);
|
||||
void NetworkAdminCompanyInfo(const Company *company, bool new_company);
|
||||
void NetworkAdminCompanyNew(const Company *company);
|
||||
void NetworkAdminCompanyUpdate(const Company *company);
|
||||
void NetworkAdminCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason bcrr);
|
||||
|
||||
void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, int64 data = 0, bool from_admin = false);
|
||||
void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, int64_t data = 0, bool from_admin = false);
|
||||
void NetworkAdminUpdate(AdminUpdateFrequency freq);
|
||||
void NetworkServerSendAdminRcon(AdminIndex admin_index, TextColour colour_code, const std::string_view string);
|
||||
void NetworkAdminConsole(const std::string_view origin, const std::string_view string);
|
||||
void NetworkAdminGameScript(const std::string_view json);
|
||||
void NetworkAdminCmdLogging(const NetworkClientSocket *owner, const CommandPacket *cp);
|
||||
void NetworkAdminCmdLogging(const NetworkClientSocket *owner, const CommandPacket &cp);
|
||||
|
||||
#endif /* NETWORK_ADMIN_H */
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "core/address.h"
|
||||
#include "../core/pool_type.hpp"
|
||||
#include "../company_type.h"
|
||||
#include "../date_type.h"
|
||||
#include "../timer/timer_game_economy.h"
|
||||
|
||||
/** Type for the pool with client information. */
|
||||
typedef Pool<NetworkClientInfo, ClientIndex, 8, MAX_CLIENT_SLOTS, PT_NCLIENT> NetworkClientInfoPool;
|
||||
@@ -25,7 +25,7 @@ struct NetworkClientInfo : NetworkClientInfoPool::PoolItem<&_networkclientinfo_p
|
||||
ClientID client_id; ///< Client identifier (same as ClientState->client_id)
|
||||
std::string client_name; ///< Name of the client
|
||||
CompanyID client_playas; ///< As which company is this client playing (CompanyID)
|
||||
Date join_date; ///< Gamedate the client has joined
|
||||
TimerGameEconomy::Date join_date; ///< Gamedate the client has joined
|
||||
|
||||
/**
|
||||
* Create a new client.
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "../toolbar_gui.h"
|
||||
#include "../core/geometry_func.hpp"
|
||||
#include "../zoom_func.h"
|
||||
#include "../timer/timer.h"
|
||||
#include "../timer/timer_window.h"
|
||||
#include "network.h"
|
||||
#include "network_client.h"
|
||||
#include "network_base.h"
|
||||
@@ -26,15 +28,8 @@
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
#include <stdarg.h> /* va_list */
|
||||
#include <deque>
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/** The draw buffer must be able to contain the chat message, client name and the "[All]" message,
|
||||
* some spaces and possible translations of [All] to other languages. */
|
||||
static_assert((int)DRAW_STRING_BUFFER >= (int)NETWORK_CHAT_LENGTH + NETWORK_NAME_LENGTH + 40);
|
||||
|
||||
/** Spacing between chat lines. */
|
||||
static const uint NETWORK_CHAT_LINE_SPACING = 3;
|
||||
|
||||
@@ -63,7 +58,7 @@ static std::chrono::steady_clock::time_point _chatmessage_dirty_time;
|
||||
* the left and pixels from the bottom. The height is the maximum height.
|
||||
*/
|
||||
static PointDimension _chatmsg_box;
|
||||
static uint8 *_chatmessage_backup = nullptr; ///< Backup in case text is moved.
|
||||
static ReusableBuffer<uint8_t> _chatmessage_backup; ///< Backup in case text is moved.
|
||||
|
||||
/**
|
||||
* Test if there are any chat messages to display.
|
||||
@@ -72,7 +67,7 @@ static uint8 *_chatmessage_backup = nullptr; ///< Backup in case text is moved.
|
||||
*/
|
||||
static inline bool HaveChatMessages(bool show_all)
|
||||
{
|
||||
if (show_all) return _chatmsg_list.size() != 0;
|
||||
if (show_all) return !_chatmsg_list.empty();
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
for (auto &cmsg : _chatmsg_list) {
|
||||
@@ -86,7 +81,7 @@ static inline bool HaveChatMessages(bool show_all)
|
||||
* Add a text message to the 'chat window' to be shown
|
||||
* @param colour The colour this message is to be shown in
|
||||
* @param duration The duration of the chat message in seconds
|
||||
* @param message message itself in printf() style
|
||||
* @param message message itself
|
||||
*/
|
||||
void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const std::string &message)
|
||||
{
|
||||
@@ -106,9 +101,8 @@ void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const std::st
|
||||
/** Initialize all font-dependent chat box sizes. */
|
||||
void NetworkReInitChatBoxSize()
|
||||
{
|
||||
_chatmsg_box.y = 3 * FONT_HEIGHT_NORMAL;
|
||||
_chatmsg_box.height = MAX_CHAT_MESSAGES * (FONT_HEIGHT_NORMAL + ScaleGUITrad(NETWORK_CHAT_LINE_SPACING)) + ScaleGUITrad(4);
|
||||
_chatmessage_backup = ReallocT(_chatmessage_backup, _chatmsg_box.width * _chatmsg_box.height * BlitterFactory::GetCurrentBlitter()->GetBytesPerPixel());
|
||||
_chatmsg_box.y = 3 * GetCharacterHeight(FS_NORMAL);
|
||||
_chatmsg_box.height = MAX_CHAT_MESSAGES * (GetCharacterHeight(FS_NORMAL) + ScaleGUITrad(NETWORK_CHAT_LINE_SPACING)) + ScaleGUITrad(4);
|
||||
}
|
||||
|
||||
/** Initialize all buffers of the chat visualisation. */
|
||||
@@ -161,7 +155,7 @@ void NetworkUndrawChatMessage()
|
||||
|
||||
_chatmessage_visible = false;
|
||||
/* Put our 'shot' back to the screen */
|
||||
blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup, width, height);
|
||||
blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup.GetBuffer(), width, height);
|
||||
/* And make sure it is updated next time */
|
||||
VideoDriver::GetInstance()->MakeDirty(x, y, width, height);
|
||||
|
||||
@@ -170,9 +164,8 @@ void NetworkUndrawChatMessage()
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if a message is expired. */
|
||||
void NetworkChatMessageLoop()
|
||||
{
|
||||
/** Check if a message is expired on a regular interval. */
|
||||
static IntervalTimer<TimerWindow> network_message_expired_interval(std::chrono::seconds(1), [](auto) {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
for (auto &cmsg : _chatmsg_list) {
|
||||
/* Message has expired, remove from the list */
|
||||
@@ -182,7 +175,7 @@ void NetworkChatMessageLoop()
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/** Draw the chat message-box */
|
||||
void NetworkDrawChatMessage()
|
||||
@@ -214,10 +207,9 @@ void NetworkDrawChatMessage()
|
||||
}
|
||||
if (width <= 0 || height <= 0) return;
|
||||
|
||||
assert(blitter->BufferSize(width, height) <= (int)(_chatmsg_box.width * _chatmsg_box.height * blitter->GetBytesPerPixel()));
|
||||
|
||||
/* Make a copy of the screen as it is before painting (for undraw) */
|
||||
blitter->CopyToBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup, width, height);
|
||||
uint8_t *buffer = _chatmessage_backup.Allocate(BlitterFactory::GetCurrentBlitter()->BufferSize(width, height));
|
||||
blitter->CopyToBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), buffer, width, height);
|
||||
|
||||
_cur_dpi = &_screen; // switch to _screen painting
|
||||
|
||||
@@ -226,10 +218,10 @@ void NetworkDrawChatMessage()
|
||||
for (auto &cmsg : _chatmsg_list) {
|
||||
if (!show_all && cmsg.remove_time < now) continue;
|
||||
SetDParamStr(0, cmsg.message);
|
||||
string_height += GetStringLineCount(STR_JUST_RAW_STRING, width - 1) * FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING;
|
||||
string_height += GetStringLineCount(STR_JUST_RAW_STRING, width - 1) * GetCharacterHeight(FS_NORMAL) + NETWORK_CHAT_LINE_SPACING;
|
||||
}
|
||||
|
||||
string_height = std::min<uint>(string_height, MAX_CHAT_MESSAGES * (FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING));
|
||||
string_height = std::min<uint>(string_height, MAX_CHAT_MESSAGES * (GetCharacterHeight(FS_NORMAL) + NETWORK_CHAT_LINE_SPACING));
|
||||
|
||||
int top = _screen.height - _chatmsg_box.y - string_height - 2;
|
||||
int bottom = _screen.height - _chatmsg_box.y - 2;
|
||||
@@ -308,13 +300,13 @@ struct NetworkChatWindow : public Window {
|
||||
PositionNetworkChatWindow(this);
|
||||
}
|
||||
|
||||
void Close() override
|
||||
void Close([[maybe_unused]] int data = 0) override
|
||||
{
|
||||
InvalidateWindowData(WC_NEWS_WINDOW, 0, 0);
|
||||
this->Window::Close();
|
||||
}
|
||||
|
||||
void FindWindowPlacementAndResize(int def_width, int def_height) override
|
||||
void FindWindowPlacementAndResize([[maybe_unused]] int def_width, [[maybe_unused]] int def_height) override
|
||||
{
|
||||
Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
|
||||
}
|
||||
@@ -323,18 +315,16 @@ struct NetworkChatWindow : public Window {
|
||||
* Find the next item of the list of things that can be auto-completed.
|
||||
* @param item The current indexed item to return. This function can, and most
|
||||
* likely will, alter item, to skip empty items in the arrays.
|
||||
* @return Returns the char that matched to the index.
|
||||
* @return Returns the view that matched to the index.
|
||||
*/
|
||||
const char *ChatTabCompletionNextItem(uint *item)
|
||||
std::optional<std::string> ChatTabCompletionNextItem(uint *item)
|
||||
{
|
||||
static char chat_tab_temp_buffer[64];
|
||||
|
||||
/* First, try clients */
|
||||
if (*item < MAX_CLIENT_SLOTS) {
|
||||
/* Skip inactive clients */
|
||||
for (NetworkClientInfo *ci : NetworkClientInfo::Iterate(*item)) {
|
||||
*item = ci->index;
|
||||
return ci->client_name.c_str();
|
||||
return ci->client_name;
|
||||
}
|
||||
*item = MAX_CLIENT_SLOTS;
|
||||
}
|
||||
@@ -346,12 +336,11 @@ struct NetworkChatWindow : public Window {
|
||||
for (const Town *t : Town::Iterate(*item - MAX_CLIENT_SLOTS)) {
|
||||
/* Get the town-name via the string-system */
|
||||
SetDParam(0, t->index);
|
||||
GetString(chat_tab_temp_buffer, STR_TOWN_NAME, lastof(chat_tab_temp_buffer));
|
||||
return &chat_tab_temp_buffer[0];
|
||||
return GetString(STR_TOWN_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,13 +348,14 @@ struct NetworkChatWindow : public Window {
|
||||
* the word right from that as to complete. It also writes a \0 at the
|
||||
* position of the space (if any). If nothing found, buf is returned.
|
||||
*/
|
||||
static char *ChatTabCompletionFindText(char *buf)
|
||||
static std::string_view ChatTabCompletionFindText(std::string_view &buf)
|
||||
{
|
||||
char *p = strrchr(buf, ' ');
|
||||
if (p == nullptr) return buf;
|
||||
auto it = buf.find_last_of(' ');
|
||||
if (it == std::string_view::npos) return buf;
|
||||
|
||||
*p = '\0';
|
||||
return p + 1;
|
||||
std::string_view res = buf.substr(it + 1);
|
||||
buf.remove_suffix(res.size() + 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,46 +363,44 @@ struct NetworkChatWindow : public Window {
|
||||
*/
|
||||
void ChatTabCompletion()
|
||||
{
|
||||
static char _chat_tab_completion_buf[NETWORK_CHAT_LENGTH];
|
||||
assert(this->message_editbox.text.max_bytes == lengthof(_chat_tab_completion_buf));
|
||||
static std::string _chat_tab_completion_buf;
|
||||
|
||||
Textbuf *tb = &this->message_editbox.text;
|
||||
size_t len, tb_len;
|
||||
uint item;
|
||||
char *tb_buf, *pre_buf;
|
||||
const char *cur_name;
|
||||
uint item = 0;
|
||||
bool second_scan = false;
|
||||
|
||||
item = 0;
|
||||
/* Create views, so we do not need to copy the data for now. */
|
||||
std::string_view pre_buf = _chat_tab_completion_active ? std::string_view(_chat_tab_completion_buf) : std::string_view(tb->buf);
|
||||
std::string_view tb_buf = ChatTabCompletionFindText(pre_buf);
|
||||
|
||||
/* Copy the buffer so we can modify it without damaging the real data */
|
||||
pre_buf = (_chat_tab_completion_active) ? stredup(_chat_tab_completion_buf) : stredup(tb->buf);
|
||||
/*
|
||||
* Comparing pointers of the data, as both "Hi:<tab>" and "Hi: Hi:<tab>" will result in
|
||||
* tb_buf and pre_buf being "Hi:", which would be equal in content but not in context.
|
||||
*/
|
||||
bool begin_of_line = tb_buf.data() == pre_buf.data();
|
||||
|
||||
tb_buf = ChatTabCompletionFindText(pre_buf);
|
||||
tb_len = strlen(tb_buf);
|
||||
|
||||
while ((cur_name = ChatTabCompletionNextItem(&item)) != nullptr) {
|
||||
std::optional<std::string> cur_item;
|
||||
while ((cur_item = ChatTabCompletionNextItem(&item)).has_value()) {
|
||||
std::string_view cur_name = cur_item.value();
|
||||
item++;
|
||||
|
||||
if (_chat_tab_completion_active) {
|
||||
/* We are pressing TAB again on the same name, is there another name
|
||||
* that starts with this? */
|
||||
if (!second_scan) {
|
||||
size_t offset;
|
||||
size_t length;
|
||||
std::string_view view;
|
||||
|
||||
/* If we are completing at the begin of the line, skip the ': ' we added */
|
||||
if (tb_buf == pre_buf) {
|
||||
offset = 0;
|
||||
length = (tb->bytes - 1) - 2;
|
||||
if (begin_of_line) {
|
||||
view = std::string_view(tb->buf, (tb->bytes - 1) - 2);
|
||||
} else {
|
||||
/* Else, find the place we are completing at */
|
||||
offset = strlen(pre_buf) + 1;
|
||||
length = (tb->bytes - 1) - offset;
|
||||
size_t offset = pre_buf.size() + 1;
|
||||
view = std::string_view(tb->buf + offset, (tb->bytes - 1) - offset);
|
||||
}
|
||||
|
||||
/* Compare if we have a match */
|
||||
if (strlen(cur_name) == length && strncmp(cur_name, tb->buf + offset, length) == 0) second_scan = true;
|
||||
if (cur_name == view) second_scan = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -420,21 +408,19 @@ struct NetworkChatWindow : public Window {
|
||||
/* Now any match we make on _chat_tab_completion_buf after this, is perfect */
|
||||
}
|
||||
|
||||
len = strlen(cur_name);
|
||||
if (tb_len < len && strncasecmp(cur_name, tb_buf, tb_len) == 0) {
|
||||
if (tb_buf.size() < cur_name.size() && cur_name.starts_with(tb_buf)) {
|
||||
/* Save the data it was before completion */
|
||||
if (!second_scan) seprintf(_chat_tab_completion_buf, lastof(_chat_tab_completion_buf), "%s", tb->buf);
|
||||
if (!second_scan) _chat_tab_completion_buf = tb->buf;
|
||||
_chat_tab_completion_active = true;
|
||||
|
||||
/* Change to the found name. Add ': ' if we are at the start of the line (pretty) */
|
||||
if (pre_buf == tb_buf) {
|
||||
this->message_editbox.text.Print("%s: ", cur_name);
|
||||
if (begin_of_line) {
|
||||
this->message_editbox.text.Assign(fmt::format("{}: ", cur_name));
|
||||
} else {
|
||||
this->message_editbox.text.Print("%s %s", pre_buf, cur_name);
|
||||
this->message_editbox.text.Assign(fmt::format("{} {}", pre_buf, cur_name));
|
||||
}
|
||||
|
||||
this->SetDirty();
|
||||
free(pre_buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -446,16 +432,15 @@ struct NetworkChatWindow : public Window {
|
||||
|
||||
this->SetDirty();
|
||||
}
|
||||
free(pre_buf);
|
||||
}
|
||||
|
||||
Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override
|
||||
Point OnInitialPosition([[maybe_unused]] int16_t sm_width, [[maybe_unused]] int16_t sm_height, [[maybe_unused]] int window_number) override
|
||||
{
|
||||
Point pt = { 0, _screen.height - sm_height - FindWindowById(WC_STATUS_BAR, 0)->height };
|
||||
return pt;
|
||||
}
|
||||
|
||||
void SetStringParameters(int widget) const override
|
||||
void SetStringParameters(WidgetID widget) const override
|
||||
{
|
||||
if (widget != WID_NC_DESTINATION) return;
|
||||
|
||||
@@ -464,12 +449,12 @@ struct NetworkChatWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_NC_SENDBUTTON: /* Send */
|
||||
SendChat(this->message_editbox.text.buf, this->dtype, this->dest);
|
||||
FALLTHROUGH;
|
||||
[[fallthrough]];
|
||||
|
||||
case WID_NC_CLOSE: /* Cancel */
|
||||
this->Close();
|
||||
@@ -477,7 +462,7 @@ struct NetworkChatWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
EventState OnKeyPress(WChar key, uint16 keycode) override
|
||||
EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
|
||||
{
|
||||
EventState state = ES_NOT_HANDLED;
|
||||
if (keycode == WKC_TAB) {
|
||||
@@ -487,9 +472,11 @@ struct NetworkChatWindow : public Window {
|
||||
return state;
|
||||
}
|
||||
|
||||
void OnEditboxChanged(int wid) override
|
||||
void OnEditboxChanged(WidgetID widget) override
|
||||
{
|
||||
_chat_tab_completion_active = false;
|
||||
if (widget == WID_NC_TEXTBOX) {
|
||||
_chat_tab_completion_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -497,14 +484,14 @@ struct NetworkChatWindow : public Window {
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
|
||||
{
|
||||
if (data == this->dest) this->Close();
|
||||
}
|
||||
};
|
||||
|
||||
/** The widgets of the chat window. */
|
||||
static const NWidgetPart _nested_chat_window_widgets[] = {
|
||||
static constexpr NWidgetPart _nested_chat_window_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_GREY, WID_NC_CLOSE),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_NC_BACKGROUND),
|
||||
@@ -519,11 +506,11 @@ static const NWidgetPart _nested_chat_window_widgets[] = {
|
||||
};
|
||||
|
||||
/** The description of the chat window. */
|
||||
static WindowDesc _chat_window_desc(
|
||||
static WindowDesc _chat_window_desc(__FILE__, __LINE__,
|
||||
WDP_MANUAL, nullptr, 0, 0,
|
||||
WC_SEND_NETWORK_MSG, WC_NONE,
|
||||
0,
|
||||
_nested_chat_window_widgets, lengthof(_nested_chat_window_widgets)
|
||||
std::begin(_nested_chat_window_widgets), std::end(_nested_chat_window_widgets)
|
||||
);
|
||||
|
||||
|
||||
|
||||
+255
-158
@@ -20,7 +20,8 @@
|
||||
#include "../company_gui.h"
|
||||
#include "../company_cmd.h"
|
||||
#include "../core/random_func.hpp"
|
||||
#include "../date_func.h"
|
||||
#include "../timer/timer_game_tick.h"
|
||||
#include "../timer/timer_game_calendar.h"
|
||||
#include "../gfx_func.h"
|
||||
#include "../error.h"
|
||||
#include "../rev.h"
|
||||
@@ -30,6 +31,7 @@
|
||||
#include "network_gamelist.h"
|
||||
#include "../core/backup_type.hpp"
|
||||
#include "../thread.h"
|
||||
#include "../social_integration.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
@@ -79,19 +81,19 @@ struct PacketReader : LoadFilter {
|
||||
* Add a packet to this buffer.
|
||||
* @param p The packet to add.
|
||||
*/
|
||||
void AddPacket(Packet *p)
|
||||
void AddPacket(Packet &p)
|
||||
{
|
||||
assert(this->read_bytes == 0);
|
||||
p->TransferOutWithLimit(TransferOutMemCopy, this->bufe - this->buf, this);
|
||||
p.TransferOutWithLimit(TransferOutMemCopy, this->bufe - this->buf, this);
|
||||
|
||||
/* Did everything fit in the current chunk, then we're done. */
|
||||
if (p->RemainingBytesToTransfer() == 0) return;
|
||||
if (p.RemainingBytesToTransfer() == 0) return;
|
||||
|
||||
/* Allocate a new chunk and add the remaining data. */
|
||||
this->blocks.push_back(this->buf = CallocT<byte>(CHUNK));
|
||||
this->bufe = this->buf + CHUNK;
|
||||
|
||||
p->TransferOutWithLimit(TransferOutMemCopy, this->bufe - this->buf, this);
|
||||
p.TransferOutWithLimit(TransferOutMemCopy, this->bufe - this->buf, this);
|
||||
}
|
||||
|
||||
size_t Read(byte *rbuf, size_t size) override
|
||||
@@ -153,13 +155,14 @@ ClientNetworkGameSocketHandler::~ClientNetworkGameSocketHandler()
|
||||
assert(ClientNetworkGameSocketHandler::my_client == this);
|
||||
ClientNetworkGameSocketHandler::my_client = nullptr;
|
||||
|
||||
delete this->savegame;
|
||||
delete this->GetInfo();
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvStatus status)
|
||||
{
|
||||
assert(status != NETWORK_RECV_STATUS_OKAY);
|
||||
if (this->IsPendingDeletion()) return status;
|
||||
|
||||
assert(this->sock != INVALID_SOCKET);
|
||||
|
||||
if (!this->HasClientQuit()) {
|
||||
@@ -168,13 +171,13 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
this->SendPackets(true);
|
||||
|
||||
/* Wait a number of ticks so our leave message can reach the server.
|
||||
* This is especially needed for Windows servers as they seem to get
|
||||
* the "socket is closed" message before receiving our leave message,
|
||||
* which would trigger the server to close the connection as well. */
|
||||
* This is especially needed for Windows servers as they seem to get
|
||||
* the "socket is closed" message before receiving our leave message,
|
||||
* which would trigger the server to close the connection as well. */
|
||||
CSleep(3 * MILLISECONDS_PER_TICK);
|
||||
}
|
||||
|
||||
delete this;
|
||||
this->DeferDeletion();
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -185,6 +188,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
*/
|
||||
void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
||||
{
|
||||
if (this->IsPendingDeletion()) return;
|
||||
|
||||
/* First, send a CLIENT_ERROR to the server, so it knows we are
|
||||
* disconnected (and why!) */
|
||||
NetworkErrorCode errorno;
|
||||
@@ -223,7 +228,9 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
||||
ClientNetworkEmergencySave();
|
||||
}
|
||||
|
||||
_switch_mode = SM_MENU;
|
||||
CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
|
||||
if (_game_mode != GM_MENU) _switch_mode = SM_MENU;
|
||||
_networking = false;
|
||||
}
|
||||
|
||||
@@ -264,7 +271,6 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
||||
|
||||
NetworkExecuteLocalCommandQueue();
|
||||
|
||||
extern void StateGameLoop();
|
||||
StateGameLoop();
|
||||
|
||||
/* Check if we are in sync! */
|
||||
@@ -276,7 +282,7 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
||||
if (_sync_seed_1 != _random.state[0]) {
|
||||
#endif
|
||||
ShowNetworkError(STR_NETWORK_ERROR_DESYNC);
|
||||
Debug(desync, 1, "sync_err: {:08x}; {:02x}", _date, _date_fract);
|
||||
Debug(desync, 1, "sync_err: {:08x}; {:02x}", TimerGameEconomy::date, TimerGameEconomy::date_fract);
|
||||
Debug(net, 0, "Sync error detected");
|
||||
my_client->ClientError(NETWORK_RECV_STATUS_DESYNC);
|
||||
return false;
|
||||
@@ -305,15 +311,15 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
||||
ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = nullptr;
|
||||
|
||||
/** Last frame we performed an ack. */
|
||||
static uint32 last_ack_frame;
|
||||
static uint32_t last_ack_frame;
|
||||
|
||||
/** One bit of 'entropy' used to generate a salt for the company passwords. */
|
||||
static uint32 _password_game_seed;
|
||||
static uint32_t _password_game_seed;
|
||||
/** The other bit of 'entropy' used to generate a salt for the company passwords. */
|
||||
static std::string _password_server_id;
|
||||
|
||||
/** Maximum number of companies of the currently joined server. */
|
||||
static uint8 _network_server_max_companies;
|
||||
static uint8_t _network_server_max_companies;
|
||||
/** The current name of the server you are on. */
|
||||
std::string _network_server_name;
|
||||
|
||||
@@ -321,35 +327,40 @@ std::string _network_server_name;
|
||||
NetworkJoinInfo _network_join;
|
||||
|
||||
/** Make sure the server ID length is the same as a md5 hash. */
|
||||
static_assert(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1);
|
||||
static_assert(NETWORK_SERVER_ID_LENGTH == MD5_HASH_BYTES * 2 + 1);
|
||||
|
||||
/***********
|
||||
* Sending functions
|
||||
* DEF_CLIENT_SEND_COMMAND has no parameters
|
||||
************/
|
||||
|
||||
/** Tell the server we would like to join. */
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendJoin()
|
||||
{
|
||||
Debug(net, 9, "Client::SendJoin()");
|
||||
|
||||
Debug(net, 9, "Client::status = JOIN");
|
||||
my_client->status = STATUS_JOIN;
|
||||
Debug(net, 9, "Client::join_status = AUTHORIZING");
|
||||
_network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING;
|
||||
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
|
||||
Packet *p = new Packet(PACKET_CLIENT_JOIN);
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_JOIN);
|
||||
p->Send_string(GetNetworkRevisionString());
|
||||
p->Send_uint32(_openttd_newgrf_version);
|
||||
p->Send_string(_settings_client.network.client_name); // Client name
|
||||
p->Send_uint8 (_network_join.company); // PlayAs
|
||||
p->Send_uint8 (0); // Used to be language
|
||||
my_client->SendPacket(p);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Tell the server we got all the NewGRFs. */
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendNewGRFsOk()
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_NEWGRFS_CHECKED);
|
||||
my_client->SendPacket(p);
|
||||
Debug(net, 9, "Client::SendNewGRFsOk()");
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_NEWGRFS_CHECKED);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
@@ -359,9 +370,11 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendNewGRFsOk()
|
||||
*/
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const std::string &password)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_GAME_PASSWORD);
|
||||
Debug(net, 9, "Client::SendGamePassword()");
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_GAME_PASSWORD);
|
||||
p->Send_string(password);
|
||||
my_client->SendPacket(p);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
@@ -371,40 +384,50 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const std::st
|
||||
*/
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const std::string &password)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_COMPANY_PASSWORD);
|
||||
Debug(net, 9, "Client::SendCompanyPassword()");
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_COMPANY_PASSWORD);
|
||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
||||
my_client->SendPacket(p);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Request the map from the server. */
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendGetMap()
|
||||
{
|
||||
Debug(net, 9, "Client::SendGetMap()");
|
||||
|
||||
Debug(net, 9, "Client::status = MAP_WAIT");
|
||||
my_client->status = STATUS_MAP_WAIT;
|
||||
|
||||
Packet *p = new Packet(PACKET_CLIENT_GETMAP);
|
||||
my_client->SendPacket(p);
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_GETMAP);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Tell the server we received the complete map. */
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendMapOk()
|
||||
{
|
||||
Debug(net, 9, "Client::SendMapOk()");
|
||||
|
||||
Debug(net, 9, "Client::status = ACTIVE");
|
||||
my_client->status = STATUS_ACTIVE;
|
||||
|
||||
Packet *p = new Packet(PACKET_CLIENT_MAP_OK);
|
||||
my_client->SendPacket(p);
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_MAP_OK);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Send an acknowledgement from the server's ticks. */
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendAck()
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_ACK);
|
||||
Debug(net, 9, "Client::SendAck()");
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_ACK);
|
||||
|
||||
p->Send_uint32(_frame_counter);
|
||||
p->Send_uint8 (my_client->token);
|
||||
my_client->SendPacket(p);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
@@ -412,19 +435,23 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendAck()
|
||||
* Send a command to the server.
|
||||
* @param cp The command to send.
|
||||
*/
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCommand(const CommandPacket *cp)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCommand(const CommandPacket &cp)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_COMMAND);
|
||||
my_client->NetworkGameSocketHandler::SendCommand(p, cp);
|
||||
Debug(net, 9, "Client::SendCommand(): cmd={}", cp.cmd);
|
||||
|
||||
my_client->SendPacket(p);
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_COMMAND);
|
||||
my_client->NetworkGameSocketHandler::SendCommand(*p, cp);
|
||||
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Send a chat-packet over the network */
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64 data)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64_t data)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_CHAT);
|
||||
Debug(net, 9, "Client::SendChat(): action={}, type={}, dest={}", action, type, dest);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_CHAT);
|
||||
|
||||
p->Send_uint8 (action);
|
||||
p->Send_uint8 (type);
|
||||
@@ -432,17 +459,19 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendChat(NetworkAction action,
|
||||
p->Send_string(msg);
|
||||
p->Send_uint64(data);
|
||||
|
||||
my_client->SendPacket(p);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Send an error-packet over the network */
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendError(NetworkErrorCode errorno)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_ERROR);
|
||||
Debug(net, 9, "Client::SendError(): errorno={}", errorno);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_ERROR);
|
||||
|
||||
p->Send_uint8(errorno);
|
||||
my_client->SendPacket(p);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
@@ -452,10 +481,12 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendError(NetworkErrorCode err
|
||||
*/
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetPassword(const std::string &password)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_SET_PASSWORD);
|
||||
Debug(net, 9, "Client::SendSetPassword()");
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_SET_PASSWORD);
|
||||
|
||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
||||
my_client->SendPacket(p);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
@@ -465,10 +496,12 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetPassword(const std::str
|
||||
*/
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetName(const std::string &name)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_SET_NAME);
|
||||
Debug(net, 9, "Client::SendSetName()");
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_SET_NAME);
|
||||
|
||||
p->Send_string(name);
|
||||
my_client->SendPacket(p);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
@@ -477,9 +510,11 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetName(const std::string
|
||||
*/
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendQuit()
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_QUIT);
|
||||
Debug(net, 9, "Client::SendSetName()");
|
||||
|
||||
my_client->SendPacket(p);
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_QUIT);
|
||||
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
@@ -490,10 +525,12 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendQuit()
|
||||
*/
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(const std::string &pass, const std::string &command)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_RCON);
|
||||
Debug(net, 9, "Client::SendRCon()");
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_RCON);
|
||||
p->Send_string(pass);
|
||||
p->Send_string(command);
|
||||
my_client->SendPacket(p);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
@@ -504,10 +541,12 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(const std::string &pa
|
||||
*/
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendMove(CompanyID company, const std::string &password)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_MOVE);
|
||||
Debug(net, 9, "Client::SendMove(): company={}", company);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_MOVE);
|
||||
p->Send_uint8(company);
|
||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
||||
my_client->SendPacket(p);
|
||||
my_client->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
@@ -523,25 +562,26 @@ bool ClientNetworkGameSocketHandler::IsConnected()
|
||||
|
||||
/***********
|
||||
* Receiving functions
|
||||
* DEF_CLIENT_RECEIVE_COMMAND has parameter: Packet *p
|
||||
************/
|
||||
|
||||
extern bool SafeLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr);
|
||||
extern bool SafeLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, std::shared_ptr<struct LoadFilter> lf);
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FULL(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FULL(Packet &)
|
||||
{
|
||||
Debug(net, 9, "Client::Receive_SERVER_FULL()");
|
||||
|
||||
/* We try to join a server which is full */
|
||||
ShowErrorMessage(STR_NETWORK_ERROR_SERVER_FULL, INVALID_STRING_ID, WL_CRITICAL);
|
||||
CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
|
||||
return NETWORK_RECV_STATUS_SERVER_FULL;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_BANNED(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_BANNED(Packet &)
|
||||
{
|
||||
Debug(net, 9, "Client::Receive_SERVER_BANNED()");
|
||||
|
||||
/* We try to join a server where we are banned */
|
||||
ShowErrorMessage(STR_NETWORK_ERROR_SERVER_BANNED, INVALID_STRING_ID, WL_CRITICAL);
|
||||
CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
|
||||
return NETWORK_RECV_STATUS_SERVER_BANNED;
|
||||
}
|
||||
@@ -549,13 +589,15 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_BANNED(Packet *
|
||||
/* This packet contains info about the client (playas and name)
|
||||
* as client we save this in NetworkClientInfo, linked via 'client_id'
|
||||
* which is always an unique number on a server. */
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Packet &p)
|
||||
{
|
||||
NetworkClientInfo *ci;
|
||||
ClientID client_id = (ClientID)p->Recv_uint32();
|
||||
CompanyID playas = (CompanyID)p->Recv_uint8();
|
||||
ClientID client_id = (ClientID)p.Recv_uint32();
|
||||
CompanyID playas = (CompanyID)p.Recv_uint8();
|
||||
|
||||
std::string name = p->Recv_string(NETWORK_NAME_LENGTH);
|
||||
Debug(net, 9, "Client::Receive_SERVER_CLIENT_INFO(): client_id={}, playas={}", client_id, playas);
|
||||
|
||||
std::string name = p.Recv_string(NETWORK_NAME_LENGTH);
|
||||
|
||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||
@@ -605,7 +647,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet &p)
|
||||
{
|
||||
static const StringID network_error_strings[] = {
|
||||
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_GENERAL
|
||||
@@ -632,14 +674,15 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p
|
||||
};
|
||||
static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
|
||||
|
||||
NetworkErrorCode error = (NetworkErrorCode)p->Recv_uint8();
|
||||
NetworkErrorCode error = (NetworkErrorCode)p.Recv_uint8();
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_ERROR(): error={}", error);
|
||||
|
||||
StringID err = STR_NETWORK_ERROR_LOSTCONNECTION;
|
||||
if (error < (ptrdiff_t)lengthof(network_error_strings)) err = network_error_strings[error];
|
||||
/* In case of kicking a client, we assume there is a kick message in the packet if we can read one byte */
|
||||
if (error == NETWORK_ERROR_KICKED && p->CanReadFromPacket(1)) {
|
||||
std::string kick_msg = p->Recv_string(NETWORK_CHAT_LENGTH);
|
||||
SetDParamStr(0, kick_msg);
|
||||
if (error == NETWORK_ERROR_KICKED && p.CanReadFromPacket(1)) {
|
||||
SetDParamStr(0, p.Recv_string(NETWORK_CHAT_LENGTH));
|
||||
ShowErrorMessage(err, STR_NETWORK_ERROR_KICK_MESSAGE, WL_CRITICAL);
|
||||
} else {
|
||||
ShowErrorMessage(err, INVALID_STRING_ID, WL_CRITICAL);
|
||||
@@ -648,30 +691,28 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p
|
||||
/* Perform an emergency save if we had already entered the game */
|
||||
if (this->status == STATUS_ACTIVE) ClientNetworkEmergencySave();
|
||||
|
||||
CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
|
||||
return NETWORK_RECV_STATUS_SERVER_ERROR;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_JOIN) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
uint grf_count = p->Recv_uint8();
|
||||
uint grf_count = p.Recv_uint8();
|
||||
NetworkRecvStatus ret = NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_CHECK_NEWGRFS(): grf_count={}", grf_count);
|
||||
|
||||
/* Check all GRFs */
|
||||
for (; grf_count > 0; grf_count--) {
|
||||
GRFIdentifier c;
|
||||
DeserializeGRFIdentifier(p, &c);
|
||||
DeserializeGRFIdentifier(p, c);
|
||||
|
||||
/* Check whether we know this GRF */
|
||||
const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum);
|
||||
const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, &c.md5sum);
|
||||
if (f == nullptr) {
|
||||
/* We do not know this GRF, bail out of initialization */
|
||||
char buf[sizeof(c.md5sum) * 2 + 1];
|
||||
md5sumToString(buf, lastof(buf), c.md5sum);
|
||||
Debug(grf, 0, "NewGRF {:08X} not found; checksum {}", BSWAP32(c.grfid), buf);
|
||||
Debug(grf, 0, "NewGRF {:08X} not found; checksum {}", BSWAP32(c.grfid), FormatArrayAsHex(c.md5sum));
|
||||
ret = NETWORK_RECV_STATUS_NEWGRF_MISMATCH;
|
||||
}
|
||||
}
|
||||
@@ -686,11 +727,14 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(P
|
||||
return ret;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Packet &)
|
||||
{
|
||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
Debug(net, 9, "Client::status = AUTH_GAME");
|
||||
this->status = STATUS_AUTH_GAME;
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_NEED_GAME_PASSWORD()");
|
||||
|
||||
if (!_network_join.server_password.empty()) {
|
||||
return SendGamePassword(_network_join.server_password);
|
||||
}
|
||||
@@ -700,13 +744,16 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSW
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
Debug(net, 9, "Client::status = AUTH_COMPANY");
|
||||
this->status = STATUS_AUTH_COMPANY;
|
||||
|
||||
_password_game_seed = p->Recv_uint32();
|
||||
_password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH);
|
||||
Debug(net, 9, "Client::Receive_SERVER_NEED_COMPANY_PASSWORD()");
|
||||
|
||||
_password_game_seed = p.Recv_uint32();
|
||||
_password_server_id = p.Recv_string(NETWORK_SERVER_ID_LENGTH);
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
if (!_network_join.company_password.empty()) {
|
||||
@@ -718,66 +765,78 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PA
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
Debug(net, 9, "Client::status = AUTHORIZED");
|
||||
this->status = STATUS_AUTHORIZED;
|
||||
|
||||
_network_own_client_id = (ClientID)p->Recv_uint32();
|
||||
_network_own_client_id = (ClientID)p.Recv_uint32();
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_WELCOME(): client_id={}", _network_own_client_id);
|
||||
|
||||
/* Initialize the password hash salting variables, even if they were previously. */
|
||||
_password_game_seed = p->Recv_uint32();
|
||||
_password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH);
|
||||
_password_game_seed = p.Recv_uint32();
|
||||
_password_server_id = p.Recv_string(NETWORK_SERVER_ID_LENGTH);
|
||||
|
||||
/* Start receiving the map */
|
||||
return SendGetMap();
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WAIT(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WAIT(Packet &p)
|
||||
{
|
||||
/* We set the internal wait state when requesting the map. */
|
||||
if (this->status != STATUS_MAP_WAIT) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_WAIT()");
|
||||
|
||||
/* But... only now we set the join status to waiting, instead of requesting. */
|
||||
Debug(net, 9, "Client::join_status = WAITING");
|
||||
_network_join_status = NETWORK_JOIN_STATUS_WAITING;
|
||||
_network_join_waiting = p->Recv_uint8();
|
||||
_network_join_waiting = p.Recv_uint8();
|
||||
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_BEGIN(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_BEGIN(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_AUTHORIZED || this->status >= STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
Debug(net, 9, "Client::status = MAP");
|
||||
this->status = STATUS_MAP;
|
||||
|
||||
if (this->savegame != nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
this->savegame = new PacketReader();
|
||||
this->savegame = std::make_shared<PacketReader>();
|
||||
|
||||
_frame_counter = _frame_counter_server = _frame_counter_max = p->Recv_uint32();
|
||||
_frame_counter = _frame_counter_server = _frame_counter_max = p.Recv_uint32();
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_MAP_BEGIN(): frame_counter={}", _frame_counter);
|
||||
|
||||
_network_join_bytes = 0;
|
||||
_network_join_bytes_total = 0;
|
||||
|
||||
Debug(net, 9, "Client::join_status = DOWNLOADING");
|
||||
_network_join_status = NETWORK_JOIN_STATUS_DOWNLOADING;
|
||||
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_SIZE(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_SIZE(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
if (this->savegame == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
_network_join_bytes_total = p->Recv_uint32();
|
||||
_network_join_bytes_total = p.Recv_uint32();
|
||||
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_MAP_SIZE(): bytes_total={}", _network_join_bytes_total);
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DATA(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DATA(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
if (this->savegame == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
@@ -785,40 +844,34 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DATA(Packet
|
||||
/* We are still receiving data, put it to the file */
|
||||
this->savegame->AddPacket(p);
|
||||
|
||||
_network_join_bytes = (uint32)this->savegame->written_bytes;
|
||||
_network_join_bytes = (uint32_t)this->savegame->written_bytes;
|
||||
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet &)
|
||||
{
|
||||
if (this->status != STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
if (this->savegame == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_MAP_DONE()");
|
||||
|
||||
Debug(net, 9, "Client::join_status = PROCESSING");
|
||||
_network_join_status = NETWORK_JOIN_STATUS_PROCESSING;
|
||||
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
|
||||
/*
|
||||
* Make sure everything is set for reading.
|
||||
*
|
||||
* We need the local copy and reset this->savegame because when
|
||||
* loading fails the network gets reset upon loading the intro
|
||||
* game, which would cause us to free this->savegame twice.
|
||||
*/
|
||||
LoadFilter *lf = this->savegame;
|
||||
this->savegame = nullptr;
|
||||
lf->Reset();
|
||||
this->savegame->Reset();
|
||||
|
||||
/* The map is done downloading, load it */
|
||||
ClearErrorMessages();
|
||||
bool load_success = SafeLoad({}, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, lf);
|
||||
bool load_success = SafeLoad({}, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, this->savegame);
|
||||
this->savegame = nullptr;
|
||||
|
||||
/* Long savegame loads shouldn't affect the lag calculation! */
|
||||
this->last_packet = std::chrono::steady_clock::now();
|
||||
|
||||
if (!load_success) {
|
||||
CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
ShowErrorMessage(STR_NETWORK_ERROR_SAVEGAMEERROR, INVALID_STRING_ID, WL_CRITICAL);
|
||||
return NETWORK_RECV_STATUS_SAVEGAME;
|
||||
}
|
||||
@@ -828,6 +881,9 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
|
||||
/* Say we received the map and loaded it correctly! */
|
||||
SendMapOk();
|
||||
|
||||
/* As we skipped switch-mode, update the time we "switched". */
|
||||
_switch_mode_time = std::chrono::steady_clock::now();
|
||||
|
||||
ShowClientList();
|
||||
|
||||
/* New company/spectator (invalid company) or company we want to join is not active
|
||||
@@ -838,6 +894,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
|
||||
if (_network_join.company != COMPANY_SPECTATOR) {
|
||||
/* We have arrived and ready to start playing; send a command to make a new company;
|
||||
* the server will give us a client-id and let us in */
|
||||
Debug(net, 9, "Client::join_status = REGISTERING");
|
||||
_network_join_status = NETWORK_JOIN_STATUS_REGISTERING;
|
||||
ShowJoinStatusWindow();
|
||||
Command<CMD_COMPANY_CTRL>::SendNet(STR_NULL, _local_company, CCA_NEW, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID);
|
||||
@@ -847,39 +904,39 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
|
||||
SetLocalCompany(_network_join.company);
|
||||
}
|
||||
|
||||
SocialIntegration::EventEnterMultiplayer(Map::SizeX(), Map::SizeY());
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
_frame_counter_server = p->Recv_uint32();
|
||||
_frame_counter_max = p->Recv_uint32();
|
||||
_frame_counter_server = p.Recv_uint32();
|
||||
_frame_counter_max = p.Recv_uint32();
|
||||
#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
|
||||
/* Test if the server supports this option
|
||||
* and if we are at the frame the server is */
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
if (p->CanReadFromPacket(sizeof(uint32) + sizeof(uint32))) {
|
||||
if (p.CanReadFromPacket(sizeof(uint32_t) + sizeof(uint32_t))) {
|
||||
#else
|
||||
if (p->CanReadFromPacket(sizeof(uint32))) {
|
||||
if (p.CanReadFromPacket(sizeof(uint32_t))) {
|
||||
#endif
|
||||
_sync_frame = _frame_counter_server;
|
||||
_sync_seed_1 = p->Recv_uint32();
|
||||
_sync_seed_1 = p.Recv_uint32();
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
_sync_seed_2 = p->Recv_uint32();
|
||||
_sync_seed_2 = p.Recv_uint32();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/* Receive the token. */
|
||||
if (p->CanReadFromPacket(sizeof(uint8))) this->token = p->Recv_uint8();
|
||||
|
||||
Debug(net, 7, "Received FRAME {}", _frame_counter_server);
|
||||
if (p.CanReadFromPacket(sizeof(uint8_t))) this->token = p.Recv_uint8();
|
||||
|
||||
/* Let the server know that we received this frame correctly
|
||||
* We do this only once per day, to save some bandwidth ;) */
|
||||
if (!_network_first_time && last_ack_frame < _frame_counter) {
|
||||
last_ack_frame = _frame_counter + DAY_TICKS;
|
||||
last_ack_frame = _frame_counter + Ticks::DAY_TICKS;
|
||||
Debug(net, 7, "Sent ACK at {}", _frame_counter);
|
||||
SendAck();
|
||||
}
|
||||
@@ -887,50 +944,56 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SYNC(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SYNC(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
_sync_frame = p->Recv_uint32();
|
||||
_sync_seed_1 = p->Recv_uint32();
|
||||
_sync_frame = p.Recv_uint32();
|
||||
_sync_seed_1 = p.Recv_uint32();
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
_sync_seed_2 = p->Recv_uint32();
|
||||
_sync_seed_2 = p.Recv_uint32();
|
||||
#endif
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_SYNC(): sync_frame={}, sync_seed_1={}", _sync_frame, _sync_seed_1);
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
CommandPacket cp;
|
||||
const char *err = this->ReceiveCommand(p, &cp);
|
||||
cp.frame = p->Recv_uint32();
|
||||
cp.my_cmd = p->Recv_bool();
|
||||
const char *err = this->ReceiveCommand(p, cp);
|
||||
cp.frame = p.Recv_uint32();
|
||||
cp.my_cmd = p.Recv_bool();
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_COMMAND(): cmd={}, frame={}", cp.cmd, cp.frame);
|
||||
|
||||
if (err != nullptr) {
|
||||
IConsolePrint(CC_WARNING, "Dropping server connection due to {}.", err);
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
|
||||
this->incoming_queue.Append(&cp);
|
||||
this->incoming_queue.push_back(cp);
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
std::string name;
|
||||
const NetworkClientInfo *ci = nullptr, *ci_to;
|
||||
|
||||
NetworkAction action = (NetworkAction)p->Recv_uint8();
|
||||
ClientID client_id = (ClientID)p->Recv_uint32();
|
||||
bool self_send = p->Recv_bool();
|
||||
std::string msg = p->Recv_string(NETWORK_CHAT_LENGTH);
|
||||
int64 data = p->Recv_uint64();
|
||||
NetworkAction action = (NetworkAction)p.Recv_uint8();
|
||||
ClientID client_id = (ClientID)p.Recv_uint32();
|
||||
bool self_send = p.Recv_bool();
|
||||
std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
|
||||
int64_t data = p.Recv_uint64();
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_CHAT(): action={}, client_id={}, self_send={}", action, client_id, self_send);
|
||||
|
||||
ci_to = NetworkClientInfo::GetByClientID(client_id);
|
||||
if (ci_to == nullptr) return NETWORK_RECV_STATUS_OKAY;
|
||||
@@ -968,14 +1031,16 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p)
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_EXTERNAL_CHAT(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_EXTERNAL_CHAT(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
std::string source = p->Recv_string(NETWORK_CHAT_LENGTH);
|
||||
TextColour colour = (TextColour)p->Recv_uint16();
|
||||
std::string user = p->Recv_string(NETWORK_CHAT_LENGTH);
|
||||
std::string msg = p->Recv_string(NETWORK_CHAT_LENGTH);
|
||||
std::string source = p.Recv_string(NETWORK_CHAT_LENGTH);
|
||||
TextColour colour = (TextColour)p.Recv_uint16();
|
||||
std::string user = p.Recv_string(NETWORK_CHAT_LENGTH);
|
||||
std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_EXTERNAL_CHAT(): source={}", source);
|
||||
|
||||
if (!IsValidConsoleColour(colour)) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
@@ -984,15 +1049,17 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_EXTERNAL_CHAT(P
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
ClientID client_id = (ClientID)p->Recv_uint32();
|
||||
ClientID client_id = (ClientID)p.Recv_uint32();
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_ERROR_QUIT(): client_id={}", client_id);
|
||||
|
||||
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
|
||||
if (ci != nullptr) {
|
||||
NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, "", GetNetworkErrorMsg((NetworkErrorCode)p->Recv_uint8()));
|
||||
NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, "", GetNetworkErrorMsg((NetworkErrorCode)p.Recv_uint8()));
|
||||
delete ci;
|
||||
}
|
||||
|
||||
@@ -1001,11 +1068,13 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Pack
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
ClientID client_id = (ClientID)p->Recv_uint32();
|
||||
ClientID client_id = (ClientID)p.Recv_uint32();
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_QUIT(): client_id={}", client_id);
|
||||
|
||||
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
|
||||
if (ci != nullptr) {
|
||||
@@ -1021,11 +1090,13 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p)
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_JOIN(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_JOIN(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
ClientID client_id = (ClientID)p->Recv_uint32();
|
||||
ClientID client_id = (ClientID)p.Recv_uint32();
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_JOIN(): client_id={}", client_id);
|
||||
|
||||
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
|
||||
if (ci != nullptr) {
|
||||
@@ -1037,8 +1108,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_JOIN(Packet *p)
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet &)
|
||||
{
|
||||
Debug(net, 9, "Client::Receive_SERVER_SHUTDOWN()");
|
||||
|
||||
/* Only when we're trying to join we really
|
||||
* care about the server shutting down. */
|
||||
if (this->status >= STATUS_JOIN) {
|
||||
@@ -1050,8 +1123,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet
|
||||
return NETWORK_RECV_STATUS_SERVER_ERROR;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEWGAME(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEWGAME(Packet &)
|
||||
{
|
||||
Debug(net, 9, "Client::Receive_SERVER_NEWGAME()");
|
||||
|
||||
/* Only when we're trying to join we really
|
||||
* care about the server shutting down. */
|
||||
if (this->status >= STATUS_JOIN) {
|
||||
@@ -1067,27 +1142,31 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEWGAME(Packet
|
||||
return NETWORK_RECV_STATUS_SERVER_ERROR;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_RCON(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_RCON(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
TextColour colour_code = (TextColour)p->Recv_uint16();
|
||||
Debug(net, 9, "Client::Receive_SERVER_RCON()");
|
||||
|
||||
TextColour colour_code = (TextColour)p.Recv_uint16();
|
||||
if (!IsValidConsoleColour(colour_code)) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
std::string rcon_out = p->Recv_string(NETWORK_RCONCOMMAND_LENGTH);
|
||||
std::string rcon_out = p.Recv_string(NETWORK_RCONCOMMAND_LENGTH);
|
||||
|
||||
IConsolePrint(colour_code, rcon_out);
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MOVE(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MOVE(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
/* Nothing more in this packet... */
|
||||
ClientID client_id = (ClientID)p->Recv_uint32();
|
||||
CompanyID company_id = (CompanyID)p->Recv_uint8();
|
||||
ClientID client_id = (ClientID)p.Recv_uint32();
|
||||
CompanyID company_id = (CompanyID)p.Recv_uint8();
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_MOVE(): client_id={}, comapny_id={}", client_id, company_id);
|
||||
|
||||
if (client_id == 0) {
|
||||
/* definitely an invalid client id, debug message and do nothing. */
|
||||
@@ -1109,23 +1188,29 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MOVE(Packet *p)
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CONFIG_UPDATE(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CONFIG_UPDATE(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
_network_server_max_companies = p->Recv_uint8();
|
||||
_network_server_name = p->Recv_string(NETWORK_NAME_LENGTH);
|
||||
_network_server_max_companies = p.Recv_uint8();
|
||||
_network_server_name = p.Recv_string(NETWORK_NAME_LENGTH);
|
||||
SetWindowClassesDirty(WC_CLIENT_LIST);
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_CONFIG_UPDATE(): max_companies={}", _network_server_max_companies);
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet *p)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
_network_company_passworded = p->Recv_uint16();
|
||||
static_assert(sizeof(_network_company_passworded) <= sizeof(uint16_t));
|
||||
_network_company_passworded = p.Recv_uint16();
|
||||
SetWindowClassesDirty(WC_COMPANY);
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_COMPANY_UPDATE()");
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
@@ -1165,6 +1250,9 @@ void NetworkClient_Connected()
|
||||
_frame_counter = 0;
|
||||
_frame_counter_server = 0;
|
||||
last_ack_frame = 0;
|
||||
|
||||
Debug(net, 9, "Client::NetworkClient_Connected()");
|
||||
|
||||
/* Request the game-info */
|
||||
MyClient::SendJoin();
|
||||
}
|
||||
@@ -1292,7 +1380,7 @@ void NetworkUpdateClientName(const std::string &client_name)
|
||||
* @param msg The actual message.
|
||||
* @param data Arbitrary extra data.
|
||||
*/
|
||||
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64 data)
|
||||
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64_t data)
|
||||
{
|
||||
MyClient::SendChat(action, type, dest, msg, data);
|
||||
}
|
||||
@@ -1323,11 +1411,20 @@ bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum number of companies that are allowed by the server.
|
||||
* @return The number of companies allowed.
|
||||
*/
|
||||
uint NetworkMaxCompaniesAllowed()
|
||||
{
|
||||
return _network_server ? _settings_client.network.max_companies : _network_server_max_companies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if max_companies has been reached on the server (local check only).
|
||||
* @return true if the max value has been reached or exceeded, false otherwise.
|
||||
*/
|
||||
bool NetworkMaxCompaniesReached()
|
||||
{
|
||||
return Company::GetNumItems() >= (_network_server ? _settings_client.network.max_companies : _network_server_max_companies);
|
||||
return Company::GetNumItems() >= NetworkMaxCompaniesAllowed();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
class ClientNetworkGameSocketHandler : public ZeroedMemoryAllocator, public NetworkGameSocketHandler {
|
||||
private:
|
||||
std::string connection_string; ///< Address we are connected to.
|
||||
struct PacketReader *savegame; ///< Packet reader for reading the savegame.
|
||||
std::shared_ptr<struct PacketReader> savegame; ///< Packet reader for reading the savegame.
|
||||
byte token; ///< The token we need to send back to the server to prove we're the right client.
|
||||
|
||||
/** Status of the connection with the server. */
|
||||
@@ -40,33 +40,33 @@ protected:
|
||||
friend void NetworkClose(bool close_admins);
|
||||
static ClientNetworkGameSocketHandler *my_client; ///< This is us!
|
||||
|
||||
NetworkRecvStatus Receive_SERVER_FULL(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_BANNED(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_ERROR(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_WELCOME(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_WAIT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_MAP_SIZE(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_MAP_DATA(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_MAP_DONE(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_JOIN(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_FRAME(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_SYNC(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_COMMAND(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_CHAT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_EXTERNAL_CHAT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_QUIT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_NEWGAME(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_RCON(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_CHECK_NEWGRFS(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_MOVE(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_COMPANY_UPDATE(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_CONFIG_UPDATE(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_FULL(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_BANNED(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_ERROR(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_WELCOME(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_WAIT(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_MAP_SIZE(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_MAP_DATA(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_MAP_DONE(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_JOIN(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_FRAME(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_SYNC(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_COMMAND(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_CHAT(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_EXTERNAL_CHAT(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_QUIT(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_NEWGAME(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_RCON(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_CHECK_NEWGRFS(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_MOVE(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_COMPANY_UPDATE(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_CONFIG_UPDATE(Packet &p) override;
|
||||
|
||||
static NetworkRecvStatus SendNewGRFsOk();
|
||||
static NetworkRecvStatus SendGetMap();
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
void ClientError(NetworkRecvStatus res);
|
||||
|
||||
static NetworkRecvStatus SendJoin();
|
||||
static NetworkRecvStatus SendCommand(const CommandPacket *cp);
|
||||
static NetworkRecvStatus SendCommand(const CommandPacket &cp);
|
||||
static NetworkRecvStatus SendError(NetworkErrorCode errorno);
|
||||
static NetworkRecvStatus SendQuit();
|
||||
static NetworkRecvStatus SendAck();
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
static NetworkRecvStatus SendGamePassword(const std::string &password);
|
||||
static NetworkRecvStatus SendCompanyPassword(const std::string &password);
|
||||
|
||||
static NetworkRecvStatus SendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64 data);
|
||||
static NetworkRecvStatus SendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64_t data);
|
||||
static NetworkRecvStatus SendSetPassword(const std::string &password);
|
||||
static NetworkRecvStatus SendSetName(const std::string &name);
|
||||
static NetworkRecvStatus SendRCon(const std::string &password, const std::string &command);
|
||||
|
||||
+59
-123
@@ -22,6 +22,7 @@
|
||||
#include "../dock_cmd.h"
|
||||
#include "../economy_cmd.h"
|
||||
#include "../engine_cmd.h"
|
||||
#include "../error_func.h"
|
||||
#include "../goal_cmd.h"
|
||||
#include "../group_cmd.h"
|
||||
#include "../industry_cmd.h"
|
||||
@@ -50,7 +51,6 @@
|
||||
#include "../water_cmd.h"
|
||||
#include "../waypoint_cmd.h"
|
||||
#include "../script/script_cmd.h"
|
||||
#include <array>
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -122,9 +122,9 @@ struct CallbackArgsHelper<void(*const)(Commands, const CommandCost &, Targs...)>
|
||||
/* Helpers to generate the command dispatch table from the command traits. */
|
||||
|
||||
template <Commands Tcmd> static CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data);
|
||||
template <Commands Tcmd, size_t cb> static void UnpackNetworkCommand(const CommandPacket *cp);
|
||||
template <Commands Tcmd, size_t cb> static void UnpackNetworkCommand(const CommandPacket &cp);
|
||||
template <Commands Tcmd> static void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id);
|
||||
using UnpackNetworkCommandProc = void (*)(const CommandPacket *);
|
||||
using UnpackNetworkCommandProc = void (*)(const CommandPacket &);
|
||||
using UnpackDispatchT = std::array<UnpackNetworkCommandProc, _callback_tuple_size>;
|
||||
struct CommandDispatch {
|
||||
CommandDataBuffer(*Sanitize)(const CommandDataBuffer &);
|
||||
@@ -165,76 +165,6 @@ static constexpr auto _cmd_dispatch = MakeDispatchTable(std::make_integer_sequen
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Append a CommandPacket at the end of the queue.
|
||||
* @param p The packet to append to the queue.
|
||||
* @note A new instance of the CommandPacket will be made.
|
||||
*/
|
||||
void CommandQueue::Append(CommandPacket *p)
|
||||
{
|
||||
CommandPacket *add = new CommandPacket();
|
||||
*add = *p;
|
||||
add->next = nullptr;
|
||||
if (this->first == nullptr) {
|
||||
this->first = add;
|
||||
} else {
|
||||
this->last->next = add;
|
||||
}
|
||||
this->last = add;
|
||||
this->count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first item in the queue and remove it from the queue.
|
||||
* @param ignore_paused Whether to ignore commands that may not be executed while paused.
|
||||
* @return the first item in the queue.
|
||||
*/
|
||||
CommandPacket *CommandQueue::Pop(bool ignore_paused)
|
||||
{
|
||||
CommandPacket **prev = &this->first;
|
||||
CommandPacket *ret = this->first;
|
||||
CommandPacket *prev_item = nullptr;
|
||||
if (ignore_paused && _pause_mode != PM_UNPAUSED) {
|
||||
while (ret != nullptr && !IsCommandAllowedWhilePaused(ret->cmd)) {
|
||||
prev_item = ret;
|
||||
prev = &ret->next;
|
||||
ret = ret->next;
|
||||
}
|
||||
}
|
||||
if (ret != nullptr) {
|
||||
if (ret == this->last) this->last = prev_item;
|
||||
*prev = ret->next;
|
||||
this->count--;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first item in the queue, but don't remove it.
|
||||
* @param ignore_paused Whether to ignore commands that may not be executed while paused.
|
||||
* @return the first item in the queue.
|
||||
*/
|
||||
CommandPacket *CommandQueue::Peek(bool ignore_paused)
|
||||
{
|
||||
if (!ignore_paused || _pause_mode == PM_UNPAUSED) return this->first;
|
||||
|
||||
for (CommandPacket *p = this->first; p != nullptr; p = p->next) {
|
||||
if (IsCommandAllowedWhilePaused(p->cmd)) return p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** Free everything that is in the queue. */
|
||||
void CommandQueue::Free()
|
||||
{
|
||||
CommandPacket *cp;
|
||||
while ((cp = this->Pop()) != nullptr) {
|
||||
delete cp;
|
||||
}
|
||||
assert(this->count == 0);
|
||||
}
|
||||
|
||||
/** Local queue of packets waiting for handling. */
|
||||
static CommandQueue _local_wait_queue;
|
||||
/** Local queue of packets waiting for execution. */
|
||||
@@ -261,17 +191,15 @@ static size_t FindCallbackIndex(CommandCallback *callback)
|
||||
* @param err_message Message prefix to show on error
|
||||
* @param callback A callback function to call after the command is finished
|
||||
* @param company The company that wants to send the command
|
||||
* @param location Location of the command (e.g. for error message position)
|
||||
* @param cmd_data The command proc arguments.
|
||||
*/
|
||||
void NetworkSendCommand(Commands cmd, StringID err_message, CommandCallback *callback, CompanyID company, TileIndex location, const CommandDataBuffer &cmd_data)
|
||||
void NetworkSendCommand(Commands cmd, StringID err_message, CommandCallback *callback, CompanyID company, const CommandDataBuffer &cmd_data)
|
||||
{
|
||||
CommandPacket c;
|
||||
c.company = company;
|
||||
c.cmd = cmd;
|
||||
c.err_msg = err_message;
|
||||
c.callback = callback;
|
||||
c.tile = location;
|
||||
c.data = cmd_data;
|
||||
|
||||
if (_network_server) {
|
||||
@@ -284,14 +212,14 @@ void NetworkSendCommand(Commands cmd, StringID err_message, CommandCallback *cal
|
||||
c.frame = _frame_counter_max + 1;
|
||||
c.my_cmd = true;
|
||||
|
||||
_local_wait_queue.Append(&c);
|
||||
_local_wait_queue.push_back(c);
|
||||
return;
|
||||
}
|
||||
|
||||
c.frame = 0; // The client can't tell which frame, so just make it 0
|
||||
|
||||
/* Clients send their command to the server and forget all about the packet */
|
||||
MyClient::SendCommand(&c);
|
||||
MyClient::SendCommand(c);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,10 +233,9 @@ void NetworkSendCommand(Commands cmd, StringID err_message, CommandCallback *cal
|
||||
*/
|
||||
void NetworkSyncCommandQueue(NetworkClientSocket *cs)
|
||||
{
|
||||
for (CommandPacket *p = _local_execution_queue.Peek(); p != nullptr; p = p->next) {
|
||||
CommandPacket c = *p;
|
||||
for (auto &p : _local_execution_queue) {
|
||||
CommandPacket &c = cs->outgoing_queue.emplace_back(p);
|
||||
c.callback = nullptr;
|
||||
cs->outgoing_queue.Append(&c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,8 +248,8 @@ void NetworkExecuteLocalCommandQueue()
|
||||
|
||||
CommandQueue &queue = (_network_server ? _local_execution_queue : ClientNetworkGameSocketHandler::my_client->incoming_queue);
|
||||
|
||||
CommandPacket *cp;
|
||||
while ((cp = queue.Peek()) != nullptr) {
|
||||
auto cp = queue.begin();
|
||||
for (; cp != queue.end(); cp++) {
|
||||
/* The queue is always in order, which means
|
||||
* that the first element will be executed first. */
|
||||
if (_frame_counter < cp->frame) break;
|
||||
@@ -330,7 +257,7 @@ void NetworkExecuteLocalCommandQueue()
|
||||
if (_frame_counter > cp->frame) {
|
||||
/* If we reach here, it means for whatever reason, we've already executed
|
||||
* past the command we need to execute. */
|
||||
error("[net] Trying to execute a packet in the past!");
|
||||
FatalError("[net] Trying to execute a packet in the past!");
|
||||
}
|
||||
|
||||
/* We can execute this command */
|
||||
@@ -338,11 +265,9 @@ void NetworkExecuteLocalCommandQueue()
|
||||
size_t cb_index = FindCallbackIndex(cp->callback);
|
||||
assert(cb_index < _callback_tuple_size);
|
||||
assert(_cmd_dispatch[cp->cmd].Unpack[cb_index] != nullptr);
|
||||
_cmd_dispatch[cp->cmd].Unpack[cb_index](cp);
|
||||
|
||||
queue.Pop();
|
||||
delete cp;
|
||||
_cmd_dispatch[cp->cmd].Unpack[cb_index](*cp);
|
||||
}
|
||||
queue.erase(queue.begin(), cp);
|
||||
|
||||
/* Local company may have changed, so we should not restore the old value */
|
||||
_current_company = _local_company;
|
||||
@@ -353,8 +278,8 @@ void NetworkExecuteLocalCommandQueue()
|
||||
*/
|
||||
void NetworkFreeLocalCommandQueue()
|
||||
{
|
||||
_local_wait_queue.Free();
|
||||
_local_execution_queue.Free();
|
||||
_local_wait_queue.clear();
|
||||
_local_execution_queue.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,13 +298,13 @@ static void DistributeCommandPacket(CommandPacket &cp, const NetworkClientSocket
|
||||
* first place. This filters that out. */
|
||||
cp.callback = (cs != owner) ? nullptr : callback;
|
||||
cp.my_cmd = (cs == owner);
|
||||
cs->outgoing_queue.Append(&cp);
|
||||
cs->outgoing_queue.push_back(cp);
|
||||
}
|
||||
}
|
||||
|
||||
cp.callback = (nullptr != owner) ? nullptr : callback;
|
||||
cp.my_cmd = (nullptr == owner);
|
||||
_local_execution_queue.Append(&cp);
|
||||
_local_execution_queue.push_back(cp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,20 +312,33 @@ static void DistributeCommandPacket(CommandPacket &cp, const NetworkClientSocket
|
||||
* @param queue The queue of commands that has to be distributed.
|
||||
* @param owner The client that owns the commands,
|
||||
*/
|
||||
static void DistributeQueue(CommandQueue *queue, const NetworkClientSocket *owner)
|
||||
static void DistributeQueue(CommandQueue &queue, const NetworkClientSocket *owner)
|
||||
{
|
||||
#ifdef DEBUG_DUMP_COMMANDS
|
||||
/* When replaying we do not want this limitation. */
|
||||
int to_go = UINT16_MAX;
|
||||
#else
|
||||
int to_go = _settings_client.network.commands_per_frame;
|
||||
if (owner == nullptr) {
|
||||
/* This is the server, use the commands_per_frame_server setting if higher */
|
||||
to_go = std::max<int>(to_go, _settings_client.network.commands_per_frame_server);
|
||||
}
|
||||
#endif
|
||||
|
||||
CommandPacket *cp;
|
||||
while (--to_go >= 0 && (cp = queue->Pop(true)) != nullptr) {
|
||||
/* Not technically the most performant way, but consider clients rarely click more than once per tick. */
|
||||
for (auto cp = queue.begin(); cp != queue.end(); /* removing some items */) {
|
||||
/* Limit the number of commands per client per tick. */
|
||||
if (--to_go < 0) break;
|
||||
|
||||
/* Do not distribute commands when paused and the command is not allowed while paused. */
|
||||
if (_pause_mode != PM_UNPAUSED && !IsCommandAllowedWhilePaused(cp->cmd)) {
|
||||
++cp;
|
||||
continue;
|
||||
}
|
||||
|
||||
DistributeCommandPacket(*cp, owner);
|
||||
NetworkAdminCmdLogging(owner, cp);
|
||||
delete cp;
|
||||
NetworkAdminCmdLogging(owner, *cp);
|
||||
cp = queue.erase(cp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,11 +346,11 @@ static void DistributeQueue(CommandQueue *queue, const NetworkClientSocket *owne
|
||||
void NetworkDistributeCommands()
|
||||
{
|
||||
/* First send the server's commands. */
|
||||
DistributeQueue(&_local_wait_queue, nullptr);
|
||||
DistributeQueue(_local_wait_queue, nullptr);
|
||||
|
||||
/* Then send the queues of the others. */
|
||||
for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
|
||||
DistributeQueue(&cs->incoming_queue, cs);
|
||||
DistributeQueue(cs->incoming_queue, cs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,20 +360,19 @@ void NetworkDistributeCommands()
|
||||
* @param cp the struct to write the data to.
|
||||
* @return an error message. When nullptr there has been no error.
|
||||
*/
|
||||
const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *cp)
|
||||
const char *NetworkGameSocketHandler::ReceiveCommand(Packet &p, CommandPacket &cp)
|
||||
{
|
||||
cp->company = (CompanyID)p->Recv_uint8();
|
||||
cp->cmd = static_cast<Commands>(p->Recv_uint16());
|
||||
if (!IsValidCommand(cp->cmd)) return "invalid command";
|
||||
if (GetCommandFlags(cp->cmd) & CMD_OFFLINE) return "single-player only command";
|
||||
cp->err_msg = p->Recv_uint16();
|
||||
cp->tile = p->Recv_uint32();
|
||||
cp->data = _cmd_dispatch[cp->cmd].Sanitize(p->Recv_buffer());
|
||||
cp.company = (CompanyID)p.Recv_uint8();
|
||||
cp.cmd = static_cast<Commands>(p.Recv_uint16());
|
||||
if (!IsValidCommand(cp.cmd)) return "invalid command";
|
||||
if (GetCommandFlags(cp.cmd) & CMD_OFFLINE) return "single-player only command";
|
||||
cp.err_msg = p.Recv_uint16();
|
||||
cp.data = _cmd_dispatch[cp.cmd].Sanitize(p.Recv_buffer());
|
||||
|
||||
byte callback = p->Recv_uint8();
|
||||
if (callback >= _callback_table.size() || _cmd_dispatch[cp->cmd].Unpack[callback] == nullptr) return "invalid callback";
|
||||
byte callback = p.Recv_uint8();
|
||||
if (callback >= _callback_table.size() || _cmd_dispatch[cp.cmd].Unpack[callback] == nullptr) return "invalid callback";
|
||||
|
||||
cp->callback = _callback_table[callback];
|
||||
cp.callback = _callback_table[callback];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -444,20 +381,19 @@ const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *c
|
||||
* @param p the packet to send it in.
|
||||
* @param cp the packet to actually send.
|
||||
*/
|
||||
void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
|
||||
void NetworkGameSocketHandler::SendCommand(Packet &p, const CommandPacket &cp)
|
||||
{
|
||||
p->Send_uint8(cp->company);
|
||||
p->Send_uint16(cp->cmd);
|
||||
p->Send_uint16(cp->err_msg);
|
||||
p->Send_uint32(cp->tile);
|
||||
p->Send_buffer(cp->data);
|
||||
p.Send_uint8(cp.company);
|
||||
p.Send_uint16(cp.cmd);
|
||||
p.Send_uint16(cp.err_msg);
|
||||
p.Send_buffer(cp.data);
|
||||
|
||||
size_t callback = FindCallbackIndex(cp->callback);
|
||||
if (callback > UINT8_MAX || _cmd_dispatch[cp->cmd].Unpack[callback] == nullptr) {
|
||||
Debug(net, 0, "Unknown callback for command; no callback sent (command: {})", cp->cmd);
|
||||
size_t callback = FindCallbackIndex(cp.callback);
|
||||
if (callback > UINT8_MAX || _cmd_dispatch[cp.cmd].Unpack[callback] == nullptr) {
|
||||
Debug(net, 0, "Unknown callback for command; no callback sent (command: {})", cp.cmd);
|
||||
callback = 0; // _callback_table[0] == nullptr
|
||||
}
|
||||
p->Send_uint8 ((uint8)callback);
|
||||
p.Send_uint8 ((uint8_t)callback);
|
||||
}
|
||||
|
||||
/** Helper to process a single ClientID argument. */
|
||||
@@ -537,8 +473,8 @@ CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data)
|
||||
* @param cp Command packet to unpack.
|
||||
*/
|
||||
template <Commands Tcmd, size_t Tcb>
|
||||
void UnpackNetworkCommand(const CommandPacket* cp)
|
||||
void UnpackNetworkCommand(const CommandPacket &cp)
|
||||
{
|
||||
auto args = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(cp->data);
|
||||
Command<Tcmd>::PostFromNet(cp->err_msg, std::get<Tcb>(_callback_tuple), cp->my_cmd, cp->tile, args);
|
||||
auto args = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(cp.data);
|
||||
Command<Tcmd>::PostFromNet(cp.err_msg, std::get<Tcb>(_callback_tuple), cp.my_cmd, args);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ ClientNetworkContentSocketHandler _network_content_client;
|
||||
/** Wrapper function for the HasProc */
|
||||
static bool HasGRFConfig(const ContentInfo *ci, bool md5sum)
|
||||
{
|
||||
return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? ci->md5sum : nullptr) != nullptr;
|
||||
return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? &ci->md5sum : nullptr) != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,34 +49,34 @@ static bool HasGRFConfig(const ContentInfo *ci, bool md5sum)
|
||||
*/
|
||||
typedef bool (*HasProc)(const ContentInfo *ci, bool md5sum);
|
||||
|
||||
bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p)
|
||||
bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet &p)
|
||||
{
|
||||
ContentInfo *ci = new ContentInfo();
|
||||
ci->type = (ContentType)p->Recv_uint8();
|
||||
ci->id = (ContentID)p->Recv_uint32();
|
||||
ci->filesize = p->Recv_uint32();
|
||||
ci->type = (ContentType)p.Recv_uint8();
|
||||
ci->id = (ContentID)p.Recv_uint32();
|
||||
ci->filesize = p.Recv_uint32();
|
||||
|
||||
ci->name = p->Recv_string(NETWORK_CONTENT_NAME_LENGTH);
|
||||
ci->version = p->Recv_string(NETWORK_CONTENT_VERSION_LENGTH);
|
||||
ci->url = p->Recv_string(NETWORK_CONTENT_URL_LENGTH);
|
||||
ci->description = p->Recv_string(NETWORK_CONTENT_DESC_LENGTH, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE);
|
||||
ci->name = p.Recv_string(NETWORK_CONTENT_NAME_LENGTH);
|
||||
ci->version = p.Recv_string(NETWORK_CONTENT_VERSION_LENGTH);
|
||||
ci->url = p.Recv_string(NETWORK_CONTENT_URL_LENGTH);
|
||||
ci->description = p.Recv_string(NETWORK_CONTENT_DESC_LENGTH, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE);
|
||||
|
||||
ci->unique_id = p->Recv_uint32();
|
||||
for (uint j = 0; j < sizeof(ci->md5sum); j++) {
|
||||
ci->md5sum[j] = p->Recv_uint8();
|
||||
ci->unique_id = p.Recv_uint32();
|
||||
for (size_t j = 0; j < ci->md5sum.size(); j++) {
|
||||
ci->md5sum[j] = p.Recv_uint8();
|
||||
}
|
||||
|
||||
uint dependency_count = p->Recv_uint8();
|
||||
uint dependency_count = p.Recv_uint8();
|
||||
ci->dependencies.reserve(dependency_count);
|
||||
for (uint i = 0; i < dependency_count; i++) {
|
||||
ContentID dependency_cid = (ContentID)p->Recv_uint32();
|
||||
ContentID dependency_cid = (ContentID)p.Recv_uint32();
|
||||
ci->dependencies.push_back(dependency_cid);
|
||||
this->reverse_dependency_map.insert({ dependency_cid, ci->id });
|
||||
}
|
||||
|
||||
uint tag_count = p->Recv_uint8();
|
||||
uint tag_count = p.Recv_uint8();
|
||||
ci->tags.reserve(tag_count);
|
||||
for (uint i = 0; i < tag_count; i++) ci->tags.push_back(p->Recv_string(NETWORK_CONTENT_TAG_LENGTH));
|
||||
for (uint i = 0; i < tag_count; i++) ci->tags.push_back(p.Recv_string(NETWORK_CONTENT_TAG_LENGTH));
|
||||
|
||||
if (!ci->IsValid()) {
|
||||
delete ci;
|
||||
@@ -144,8 +144,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p)
|
||||
|
||||
/* Do we already have a stub for this? */
|
||||
for (ContentInfo *ici : this->infos) {
|
||||
if (ici->type == ci->type && ici->unique_id == ci->unique_id &&
|
||||
memcmp(ci->md5sum, ici->md5sum, sizeof(ci->md5sum)) == 0) {
|
||||
if (ici->type == ci->type && ici->unique_id == ci->unique_id && ci->md5sum == ici->md5sum) {
|
||||
/* Preserve the name if possible */
|
||||
if (ci->name.empty()) ci->name = ici->name;
|
||||
if (ici->IsSelected()) ci->state = ici->state;
|
||||
@@ -205,7 +204,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentType type)
|
||||
|
||||
this->Connect();
|
||||
|
||||
Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_LIST);
|
||||
auto p = std::make_unique<Packet>(PACKET_CONTENT_CLIENT_INFO_LIST);
|
||||
p->Send_uint8 ((byte)type);
|
||||
p->Send_uint32(0xffffffff);
|
||||
p->Send_uint8 (1);
|
||||
@@ -220,9 +219,9 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentType type)
|
||||
p->Send_string("patchpack"); // Or what-ever the name of your patchpack is.
|
||||
p->Send_string(_openttd_content_version_patchpack);
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,18 +236,18 @@ void ClientNetworkContentSocketHandler::RequestContentList(uint count, const Con
|
||||
while (count > 0) {
|
||||
/* We can "only" send a limited number of IDs in a single packet.
|
||||
* A packet begins with the packet size and a byte for the type.
|
||||
* Then this packet adds a uint16 for the count in this packet.
|
||||
* Then this packet adds a uint16_t for the count in this packet.
|
||||
* The rest of the packet can be used for the IDs. */
|
||||
uint p_count = std::min<uint>(count, (TCP_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
|
||||
uint p_count = std::min<uint>(count, (TCP_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16_t)) / sizeof(uint32_t));
|
||||
|
||||
Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_ID, TCP_MTU);
|
||||
auto p = std::make_unique<Packet>(PACKET_CONTENT_CLIENT_INFO_ID, TCP_MTU);
|
||||
p->Send_uint16(p_count);
|
||||
|
||||
for (uint i = 0; i < p_count; i++) {
|
||||
p->Send_uint32(content_ids[i]);
|
||||
}
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
count -= p_count;
|
||||
content_ids += p_count;
|
||||
}
|
||||
@@ -266,29 +265,29 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo
|
||||
this->Connect();
|
||||
|
||||
assert(cv->size() < 255);
|
||||
assert(cv->size() < (TCP_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8)) /
|
||||
(sizeof(uint8) + sizeof(uint32) + (send_md5sum ? /*sizeof(ContentInfo::md5sum)*/16 : 0)));
|
||||
assert(cv->size() < (TCP_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8_t)) /
|
||||
(sizeof(uint8_t) + sizeof(uint32_t) + (send_md5sum ? MD5_HASH_BYTES : 0)));
|
||||
|
||||
Packet *p = new Packet(send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID, TCP_MTU);
|
||||
p->Send_uint8((uint8)cv->size());
|
||||
auto p = std::make_unique<Packet>(send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID, TCP_MTU);
|
||||
p->Send_uint8((uint8_t)cv->size());
|
||||
|
||||
for (const ContentInfo *ci : *cv) {
|
||||
p->Send_uint8((byte)ci->type);
|
||||
p->Send_uint32(ci->unique_id);
|
||||
if (!send_md5sum) continue;
|
||||
|
||||
for (uint j = 0; j < sizeof(ci->md5sum); j++) {
|
||||
for (size_t j = 0; j < ci->md5sum.size(); j++) {
|
||||
p->Send_uint8(ci->md5sum[j]);
|
||||
}
|
||||
}
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
for (ContentInfo *ci : *cv) {
|
||||
bool found = false;
|
||||
for (ContentInfo *ci2 : this->infos) {
|
||||
if (ci->type == ci2->type && ci->unique_id == ci2->unique_id &&
|
||||
(!send_md5sum || memcmp(ci->md5sum, ci2->md5sum, sizeof(ci->md5sum)) == 0)) {
|
||||
(!send_md5sum || ci->md5sum == ci2->md5sum)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -311,13 +310,6 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uin
|
||||
{
|
||||
bytes = 0;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Emscripten is loaded via an HTTPS connection. As such, it is very
|
||||
* difficult to make HTTP connections. So always use the TCP method of
|
||||
* downloading content. */
|
||||
fallback = true;
|
||||
#endif
|
||||
|
||||
ContentIDList content;
|
||||
for (const ContentInfo *ci : this->infos) {
|
||||
if (!ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) continue;
|
||||
@@ -331,7 +323,9 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uin
|
||||
/* If there's nothing to download, do nothing. */
|
||||
if (files == 0) return;
|
||||
|
||||
if (_settings_client.network.no_http_content_downloads || fallback) {
|
||||
this->isCancelled = false;
|
||||
|
||||
if (fallback) {
|
||||
this->DownloadSelectedContentFallback(content);
|
||||
} else {
|
||||
this->DownloadSelectedContentHTTP(content);
|
||||
@@ -344,25 +338,14 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uin
|
||||
*/
|
||||
void ClientNetworkContentSocketHandler::DownloadSelectedContentHTTP(const ContentIDList &content)
|
||||
{
|
||||
uint count = (uint)content.size();
|
||||
|
||||
/* 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;
|
||||
std::string content_request;
|
||||
for (const ContentID &id : content) {
|
||||
p += seprintf(p, lastof, "%d\n", id);
|
||||
content_request += std::to_string(id) + "\n";
|
||||
}
|
||||
|
||||
this->http_response_index = -1;
|
||||
|
||||
new NetworkHTTPContentConnecter(NetworkContentMirrorConnectionString(), this, NETWORK_CONTENT_MIRROR_URL, content_request);
|
||||
/* NetworkHTTPContentConnecter takes over freeing of content_request! */
|
||||
NetworkHTTPSocketHandler::Connect(NetworkContentMirrorUriString(), this, content_request);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -378,18 +361,18 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const Co
|
||||
while (count > 0) {
|
||||
/* We can "only" send a limited number of IDs in a single packet.
|
||||
* A packet begins with the packet size and a byte for the type.
|
||||
* Then this packet adds a uint16 for the count in this packet.
|
||||
* Then this packet adds a uint16_t for the count in this packet.
|
||||
* The rest of the packet can be used for the IDs. */
|
||||
uint p_count = std::min<uint>(count, (TCP_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
|
||||
uint p_count = std::min<uint>(count, (TCP_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16_t)) / sizeof(uint32_t));
|
||||
|
||||
Packet *p = new Packet(PACKET_CONTENT_CLIENT_CONTENT, TCP_MTU);
|
||||
auto p = std::make_unique<Packet>(PACKET_CONTENT_CLIENT_CONTENT, TCP_MTU);
|
||||
p->Send_uint16(p_count);
|
||||
|
||||
for (uint i = 0; i < p_count; i++) {
|
||||
p->Send_uint32(content_ids[i]);
|
||||
}
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
count -= p_count;
|
||||
content_ids += p_count;
|
||||
}
|
||||
@@ -494,16 +477,16 @@ static inline ssize_t TransferOutFWrite(FILE *file, const char *buffer, size_t a
|
||||
return fwrite(buffer, 1, amount, file);
|
||||
}
|
||||
|
||||
bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p)
|
||||
bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet &p)
|
||||
{
|
||||
if (this->curFile == nullptr) {
|
||||
delete this->curInfo;
|
||||
/* When we haven't opened a file this must be our first packet with metadata. */
|
||||
this->curInfo = new ContentInfo;
|
||||
this->curInfo->type = (ContentType)p->Recv_uint8();
|
||||
this->curInfo->id = (ContentID)p->Recv_uint32();
|
||||
this->curInfo->filesize = p->Recv_uint32();
|
||||
this->curInfo->filename = p->Recv_string(NETWORK_CONTENT_FILENAME_LENGTH);
|
||||
this->curInfo->type = (ContentType)p.Recv_uint8();
|
||||
this->curInfo->id = (ContentID)p.Recv_uint32();
|
||||
this->curInfo->filesize = p.Recv_uint32();
|
||||
this->curInfo->filename = p.Recv_string(NETWORK_CONTENT_FILENAME_LENGTH);
|
||||
|
||||
if (!this->BeforeDownload()) {
|
||||
this->CloseConnection();
|
||||
@@ -511,8 +494,8 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p)
|
||||
}
|
||||
} else {
|
||||
/* We have a file opened, thus are downloading internal content */
|
||||
size_t toRead = p->RemainingBytesToTransfer();
|
||||
if (toRead != 0 && (size_t)p->TransferOut(TransferOutFWrite, this->curFile) != toRead) {
|
||||
size_t toRead = p.RemainingBytesToTransfer();
|
||||
if (toRead != 0 && (size_t)p.TransferOut(TransferOutFWrite, this->curFile) != toRead) {
|
||||
CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
|
||||
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
|
||||
this->CloseConnection();
|
||||
@@ -592,38 +575,46 @@ void ClientNetworkContentSocketHandler::AfterDownload()
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientNetworkContentSocketHandler::IsCancelled() const
|
||||
{
|
||||
return this->isCancelled;
|
||||
}
|
||||
|
||||
/* 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.clear();
|
||||
this->http_response.shrink_to_fit();
|
||||
this->http_response_index = -2;
|
||||
|
||||
if (this->curFile != nullptr) {
|
||||
/* Revert the download progress when we are going for the old system. */
|
||||
long size = ftell(this->curFile);
|
||||
if (size > 0) this->OnDownloadProgress(this->curInfo, (int)-size);
|
||||
this->OnDownloadProgress(this->curInfo, -1);
|
||||
|
||||
fclose(this->curFile);
|
||||
this->curFile = nullptr;
|
||||
}
|
||||
|
||||
/* If we fail, download the rest via the 'old' system. */
|
||||
if (!this->isCancelled) {
|
||||
uint files, bytes;
|
||||
|
||||
this->DownloadSelectedContent(files, bytes, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t length)
|
||||
void ClientNetworkContentSocketHandler::OnReceiveData(std::unique_ptr<char[]> data, size_t length)
|
||||
{
|
||||
assert(data == nullptr || length != 0);
|
||||
assert(data.get() == nullptr || length != 0);
|
||||
|
||||
/* Ignore any latent data coming from a connection we closed. */
|
||||
if (this->http_response_index == -2) return;
|
||||
if (this->http_response_index == -2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->http_response_index == -1) {
|
||||
if (data != nullptr) {
|
||||
/* Append the rest of the response. */
|
||||
this->http_response.insert(this->http_response.end(), data, data + length);
|
||||
this->http_response.insert(this->http_response.end(), data.get(), data.get() + length);
|
||||
return;
|
||||
} else {
|
||||
/* Make sure the response is properly terminated. */
|
||||
@@ -636,13 +627,14 @@ void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t l
|
||||
|
||||
if (data != nullptr) {
|
||||
/* We have data, so write it to the file. */
|
||||
if (fwrite(data, 1, length, this->curFile) != length) {
|
||||
if (fwrite(data.get(), 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, (int)length);
|
||||
}
|
||||
|
||||
/* Nothing more to do now. */
|
||||
return;
|
||||
}
|
||||
@@ -710,19 +702,19 @@ void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t l
|
||||
check_not_null(p);
|
||||
p++; // Start after the '/'
|
||||
|
||||
char tmp[MAX_PATH];
|
||||
if (strecpy(tmp, p, lastof(tmp)) == lastof(tmp)) {
|
||||
this->OnFailure();
|
||||
return;
|
||||
}
|
||||
std::string filename = p;
|
||||
/* Remove the extension from the string. */
|
||||
for (uint i = 0; i < 2; i++) {
|
||||
p = strrchr(tmp, '.');
|
||||
check_and_terminate(p);
|
||||
auto pos = filename.find_last_of('.');
|
||||
if (pos == std::string::npos) {
|
||||
this->OnFailure();
|
||||
return;
|
||||
}
|
||||
filename.erase(pos);
|
||||
}
|
||||
|
||||
/* Copy the string, without extension, to the filename. */
|
||||
this->curInfo->filename = tmp;
|
||||
this->curInfo->filename = std::move(filename);
|
||||
|
||||
/* Request the next file. */
|
||||
if (!this->BeforeDownload()) {
|
||||
@@ -746,7 +738,8 @@ ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() :
|
||||
http_response_index(-2),
|
||||
curFile(nullptr),
|
||||
curInfo(nullptr),
|
||||
isConnecting(false)
|
||||
isConnecting(false),
|
||||
isCancelled(false)
|
||||
{
|
||||
this->lastActivity = std::chrono::steady_clock::now();
|
||||
}
|
||||
@@ -761,7 +754,7 @@ ClientNetworkContentSocketHandler::~ClientNetworkContentSocketHandler()
|
||||
}
|
||||
|
||||
/** Connect to the content server. */
|
||||
class NetworkContentConnecter : TCPConnecter {
|
||||
class NetworkContentConnecter : public TCPConnecter {
|
||||
public:
|
||||
/**
|
||||
* Initiate the connecting.
|
||||
@@ -792,14 +785,17 @@ public:
|
||||
void ClientNetworkContentSocketHandler::Connect()
|
||||
{
|
||||
if (this->sock != INVALID_SOCKET || this->isConnecting) return;
|
||||
|
||||
this->isCancelled = false;
|
||||
this->isConnecting = true;
|
||||
new NetworkContentConnecter(NetworkContentServerConnectionString());
|
||||
|
||||
TCPConnecter::Create<NetworkContentConnecter>(NetworkContentServerConnectionString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the content server.
|
||||
*/
|
||||
NetworkRecvStatus ClientNetworkContentSocketHandler::CloseConnection(bool error)
|
||||
NetworkRecvStatus ClientNetworkContentSocketHandler::CloseConnection(bool)
|
||||
{
|
||||
NetworkContentSocketHandler::CloseConnection();
|
||||
|
||||
@@ -811,6 +807,15 @@ NetworkRecvStatus ClientNetworkContentSocketHandler::CloseConnection(bool error)
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the current download.
|
||||
*/
|
||||
void ClientNetworkContentSocketHandler::Cancel(void)
|
||||
{
|
||||
this->isCancelled = true;
|
||||
this->CloseConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we received/can send some data from/to the content server and
|
||||
* when that's the case handle it appropriately
|
||||
@@ -819,6 +824,7 @@ void ClientNetworkContentSocketHandler::SendReceive()
|
||||
{
|
||||
if (this->sock == INVALID_SOCKET || this->isConnecting) return;
|
||||
|
||||
/* Close the connection to the content server after inactivity; there can still be downloads pending via HTTP. */
|
||||
if (std::chrono::steady_clock::now() > this->lastActivity + IDLE_TIMEOUT) {
|
||||
this->CloseConnection();
|
||||
return;
|
||||
@@ -1054,11 +1060,11 @@ void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci)
|
||||
* After that's done run over them once again to test their children
|
||||
* to unselect. Don't do it immediately because it'll do exactly what
|
||||
* we're doing now. */
|
||||
for (const ContentInfo *c : parents) {
|
||||
if (c->state == ContentInfo::AUTOSELECTED) this->Unselect(c->id);
|
||||
for (const ContentInfo *parent : parents) {
|
||||
if (parent->state == ContentInfo::AUTOSELECTED) this->Unselect(parent->id);
|
||||
}
|
||||
for (const ContentInfo *c : parents) {
|
||||
this->CheckDependencyState(this->GetContent(c->id));
|
||||
for (const ContentInfo *parent : parents) {
|
||||
this->CheckDependencyState(this->GetContent(parent->id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
#define NETWORK_CONTENT_H
|
||||
|
||||
#include "core/tcp_content.h"
|
||||
#include "core/tcp_http.h"
|
||||
#include "core/http.h"
|
||||
#include <unordered_map>
|
||||
#include "../core/container_func.hpp"
|
||||
|
||||
/** Vector with content info */
|
||||
typedef std::vector<ContentInfo *> ContentVector;
|
||||
@@ -30,7 +31,7 @@ struct ContentCallback {
|
||||
* Callback for when the connection has finished
|
||||
* @param success whether the connection was made or that we failed to make it
|
||||
*/
|
||||
virtual void OnConnect(bool success) {}
|
||||
virtual void OnConnect([[maybe_unused]] bool success) {}
|
||||
|
||||
/**
|
||||
* Callback for when the connection got disconnected.
|
||||
@@ -41,23 +42,23 @@ struct ContentCallback {
|
||||
* We received a content info.
|
||||
* @param ci the content info
|
||||
*/
|
||||
virtual void OnReceiveContentInfo(const ContentInfo *ci) {}
|
||||
virtual void OnReceiveContentInfo([[maybe_unused]] const ContentInfo *ci) {}
|
||||
|
||||
/**
|
||||
* We have progress in the download of a file
|
||||
* @param ci the content info of the file
|
||||
* @param bytes the number of bytes downloaded since the previous call
|
||||
*/
|
||||
virtual void OnDownloadProgress(const ContentInfo *ci, int bytes) {}
|
||||
virtual void OnDownloadProgress([[maybe_unused]] const ContentInfo *ci, [[maybe_unused]] int bytes) {}
|
||||
|
||||
/**
|
||||
* We have finished downloading a file
|
||||
* @param cid the ContentID of the downloaded file
|
||||
*/
|
||||
virtual void OnDownloadComplete(ContentID cid) {}
|
||||
virtual void OnDownloadComplete([[maybe_unused]] ContentID cid) {}
|
||||
|
||||
/** Silentium */
|
||||
virtual ~ContentCallback() {}
|
||||
virtual ~ContentCallback() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -76,12 +77,13 @@ protected:
|
||||
FILE *curFile; ///< Currently downloaded file
|
||||
ContentInfo *curInfo; ///< Information about the currently downloaded file
|
||||
bool isConnecting; ///< Whether we're connecting
|
||||
bool isCancelled; ///< Whether the download has been cancelled
|
||||
std::chrono::steady_clock::time_point lastActivity; ///< The last time there was network activity
|
||||
|
||||
friend class NetworkContentConnecter;
|
||||
|
||||
bool Receive_SERVER_INFO(Packet *p) override;
|
||||
bool Receive_SERVER_CONTENT(Packet *p) override;
|
||||
bool Receive_SERVER_INFO(Packet &p) override;
|
||||
bool Receive_SERVER_CONTENT(Packet &p) override;
|
||||
|
||||
ContentInfo *GetContent(ContentID cid) const;
|
||||
void DownloadContentInfo(ContentID cid);
|
||||
@@ -93,7 +95,8 @@ protected:
|
||||
void OnDownloadComplete(ContentID cid) override;
|
||||
|
||||
void OnFailure() override;
|
||||
void OnReceiveData(const char *data, size_t length) override;
|
||||
void OnReceiveData(std::unique_ptr<char[]> data, size_t length) override;
|
||||
bool IsCancelled() const override;
|
||||
|
||||
bool BeforeDownload();
|
||||
void AfterDownload();
|
||||
@@ -110,6 +113,7 @@ public:
|
||||
void Connect();
|
||||
void SendReceive();
|
||||
NetworkRecvStatus CloseConnection(bool error = true) override;
|
||||
void Cancel();
|
||||
|
||||
void RequestContentList(ContentType type);
|
||||
void RequestContentList(uint count, const ContentID *content_ids);
|
||||
@@ -133,7 +137,7 @@ public:
|
||||
/** Get the begin of the content inf iterator. */
|
||||
ConstContentIterator Begin() const { return this->infos.data(); }
|
||||
/** Get the nth position of the content inf iterator. */
|
||||
ConstContentIterator Get(uint32 index) const { return this->infos.data() + index; }
|
||||
ConstContentIterator Get(uint32_t index) const { return this->infos.data() + index; }
|
||||
/** Get the end of the content inf iterator. */
|
||||
ConstContentIterator End() const { return this->Begin() + this->Length(); }
|
||||
|
||||
|
||||
+141
-133
@@ -21,8 +21,7 @@
|
||||
#include "../querystring_gui.h"
|
||||
#include "../core/geometry_func.hpp"
|
||||
#include "../textfile_gui.h"
|
||||
#include "../settings_type.h"
|
||||
#include "../settings_gui.h"
|
||||
#include "../fios.h"
|
||||
#include "network_content_gui.h"
|
||||
|
||||
|
||||
@@ -44,8 +43,10 @@ struct ContentTextfileWindow : public TextfileWindow {
|
||||
|
||||
ContentTextfileWindow(TextfileType file_type, const ContentInfo *ci) : TextfileWindow(file_type), ci(ci)
|
||||
{
|
||||
const char *textfile = this->ci->GetTextfile(file_type);
|
||||
this->LoadTextfile(textfile, GetContentInfoSubDir(this->ci->type));
|
||||
this->ConstructWindow();
|
||||
|
||||
auto textfile = this->ci->GetTextfile(file_type);
|
||||
this->LoadTextfile(textfile.value(), GetContentInfoSubDir(this->ci->type));
|
||||
}
|
||||
|
||||
StringID GetTypeString() const
|
||||
@@ -65,7 +66,7 @@ struct ContentTextfileWindow : public TextfileWindow {
|
||||
}
|
||||
}
|
||||
|
||||
void SetStringParameters(int widget) const override
|
||||
void SetStringParameters(WidgetID widget) const override
|
||||
{
|
||||
if (widget == WID_TF_CAPTION) {
|
||||
SetDParam(0, this->GetTypeString());
|
||||
@@ -81,7 +82,7 @@ void ShowContentTextfileWindow(TextfileType file_type, const ContentInfo *ci)
|
||||
}
|
||||
|
||||
/** Nested widgets for the download window. */
|
||||
static const NWidgetPart _nested_network_content_download_status_window_widgets[] = {
|
||||
static constexpr NWidgetPart _nested_network_content_download_status_window_widgets[] = {
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY),
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0), SetPadding(WidgetDimensions::unscaled.modalpopup),
|
||||
@@ -93,15 +94,15 @@ static const NWidgetPart _nested_network_content_download_status_window_widgets[
|
||||
};
|
||||
|
||||
/** Window description for the download window */
|
||||
static WindowDesc _network_content_download_status_window_desc(
|
||||
static WindowDesc _network_content_download_status_window_desc(__FILE__, __LINE__,
|
||||
WDP_CENTER, nullptr, 0, 0,
|
||||
WC_NETWORK_STATUS_WINDOW, WC_NONE,
|
||||
WDF_MODAL,
|
||||
_nested_network_content_download_status_window_widgets, lengthof(_nested_network_content_download_status_window_widgets)
|
||||
std::begin(_nested_network_content_download_status_window_widgets), std::end(_nested_network_content_download_status_window_widgets)
|
||||
);
|
||||
|
||||
BaseNetworkContentDownloadStatusWindow::BaseNetworkContentDownloadStatusWindow(WindowDesc *desc) :
|
||||
Window(desc), cur_id(UINT32_MAX)
|
||||
Window(desc), downloaded_bytes(0), downloaded_files(0), cur_id(UINT32_MAX)
|
||||
{
|
||||
_network_content_client.AddCallback(this);
|
||||
_network_content_client.DownloadSelectedContent(this->total_files, this->total_bytes);
|
||||
@@ -109,13 +110,13 @@ BaseNetworkContentDownloadStatusWindow::BaseNetworkContentDownloadStatusWindow(W
|
||||
this->InitNested(WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
|
||||
}
|
||||
|
||||
void BaseNetworkContentDownloadStatusWindow::Close()
|
||||
void BaseNetworkContentDownloadStatusWindow::Close([[maybe_unused]] int data)
|
||||
{
|
||||
_network_content_client.RemoveCallback(this);
|
||||
this->Window::Close();
|
||||
}
|
||||
|
||||
void BaseNetworkContentDownloadStatusWindow::UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void BaseNetworkContentDownloadStatusWindow::UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize)
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_NCDS_PROGRESS_BAR:
|
||||
@@ -129,23 +130,23 @@ void BaseNetworkContentDownloadStatusWindow::UpdateWidgetSize(int widget, Dimens
|
||||
break;
|
||||
|
||||
case WID_NCDS_PROGRESS_TEXT:
|
||||
size->height = FONT_HEIGHT_NORMAL * 2 + WidgetDimensions::scaled.vsep_normal;
|
||||
size->height = GetCharacterHeight(FS_NORMAL) * 2 + WidgetDimensions::scaled.vsep_normal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseNetworkContentDownloadStatusWindow::DrawWidget(const Rect &r, int widget) const
|
||||
void BaseNetworkContentDownloadStatusWindow::DrawWidget(const Rect &r, WidgetID widget) const
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_NCDS_PROGRESS_BAR: {
|
||||
/* Draw the % complete with a bar and a text */
|
||||
DrawFrameRect(r, COLOUR_GREY, FR_BORDERONLY | FR_LOWERED);
|
||||
Rect ir = r.Shrink(WidgetDimensions::scaled.bevel);
|
||||
DrawFrameRect(ir.WithWidth((uint64)ir.Width() * this->downloaded_bytes / this->total_bytes, false), COLOUR_MAUVE, FR_NONE);
|
||||
DrawFrameRect(ir.WithWidth((uint64_t)ir.Width() * this->downloaded_bytes / this->total_bytes, false), COLOUR_MAUVE, FR_NONE);
|
||||
SetDParam(0, this->downloaded_bytes);
|
||||
SetDParam(1, this->total_bytes);
|
||||
SetDParam(2, this->downloaded_bytes * 100LL / this->total_bytes);
|
||||
DrawString(ir.left, ir.right, CenterBounds(ir.top, ir.bottom, FONT_HEIGHT_NORMAL), STR_CONTENT_DOWNLOAD_PROGRESS_SIZE, TC_FROMSTRING, SA_HOR_CENTER);
|
||||
DrawString(ir.left, ir.right, CenterBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), STR_CONTENT_DOWNLOAD_PROGRESS_SIZE, TC_FROMSTRING, SA_HOR_CENTER);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -175,7 +176,13 @@ void BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(const ContentInf
|
||||
this->downloaded_files++;
|
||||
}
|
||||
|
||||
this->downloaded_bytes += bytes;
|
||||
/* A negative value means we are resetting; for example, when retrying or using a fallback. */
|
||||
if (bytes < 0) {
|
||||
this->downloaded_bytes = 0;
|
||||
} else {
|
||||
this->downloaded_bytes += bytes;
|
||||
}
|
||||
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
@@ -195,7 +202,7 @@ public:
|
||||
this->parent = FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST);
|
||||
}
|
||||
|
||||
void Close() override
|
||||
void Close([[maybe_unused]] int data = 0) override
|
||||
{
|
||||
TarScanner::Mode mode = TarScanner::NONE;
|
||||
for (auto ctype : this->receivedTypes) {
|
||||
@@ -265,7 +272,6 @@ public:
|
||||
|
||||
case CONTENT_TYPE_SCENARIO:
|
||||
case CONTENT_TYPE_HEIGHTMAP:
|
||||
extern void ScanScenarios();
|
||||
ScanScenarios();
|
||||
InvalidateWindowData(WC_SAVELOAD, 0, 0);
|
||||
break;
|
||||
@@ -281,11 +287,11 @@ public:
|
||||
this->BaseNetworkContentDownloadStatusWindow::Close();
|
||||
}
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
|
||||
{
|
||||
if (widget == WID_NCDS_CANCELOK) {
|
||||
if (this->downloaded_bytes != this->total_bytes) {
|
||||
_network_content_client.CloseConnection();
|
||||
_network_content_client.Cancel();
|
||||
this->Close();
|
||||
} else {
|
||||
/* If downloading succeeded, close the online content window. This will close
|
||||
@@ -322,7 +328,7 @@ enum ContentListFilterCriteria {
|
||||
/** Window that lists the content that's at the content server */
|
||||
class NetworkContentListWindow : public Window, ContentCallback {
|
||||
/** List with content infos. */
|
||||
typedef GUIList<const ContentInfo *, ContentListFilterData &> GUIContentList;
|
||||
typedef GUIList<const ContentInfo *, std::nullptr_t, ContentListFilterData &> GUIContentList;
|
||||
|
||||
static const uint EDITBOX_MAX_SIZE = 50; ///< Maximum size of the editbox in characters.
|
||||
|
||||
@@ -341,34 +347,30 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
uint filesize_sum; ///< The sum of all selected file sizes
|
||||
Scrollbar *vscroll; ///< Cache of the vertical scrollbar
|
||||
|
||||
static char content_type_strs[CONTENT_TYPE_END][64]; ///< Cached strings for all content types.
|
||||
static std::string content_type_strs[CONTENT_TYPE_END]; ///< Cached strings for all content types.
|
||||
|
||||
/** Search external websites for content */
|
||||
void OpenExternalSearch()
|
||||
{
|
||||
extern void OpenBrowser(const char *url);
|
||||
std::string url;
|
||||
url.reserve(1024);
|
||||
|
||||
char url[1024];
|
||||
const char *last = lastof(url);
|
||||
|
||||
char *pos = strecpy(url, "https://grfsearch.openttd.org/?", last);
|
||||
url += "https://grfsearch.openttd.org/?";
|
||||
|
||||
if (this->auto_select) {
|
||||
pos = strecpy(pos, "do=searchgrfid&q=", last);
|
||||
url += "do=searchgrfid&q=";
|
||||
|
||||
bool first = true;
|
||||
for (const ContentInfo *ci : this->content) {
|
||||
if (ci->state != ContentInfo::DOES_NOT_EXIST) continue;
|
||||
|
||||
if (!first) pos = strecpy(pos, ",", last);
|
||||
if (!first) url.push_back(',');
|
||||
first = false;
|
||||
|
||||
pos += seprintf(pos, last, "%08X", ci->unique_id);
|
||||
pos = strecpy(pos, ":", last);
|
||||
pos = md5sumToString(pos, last, ci->md5sum);
|
||||
fmt::format_to(std::back_inserter(url), "{:08X}:{}", ci->unique_id, FormatArrayAsHex(ci->md5sum));
|
||||
}
|
||||
} else {
|
||||
pos = strecpy(pos, "do=searchtext&q=", last);
|
||||
url += "do=searchtext&q=";
|
||||
|
||||
/* Escape search term */
|
||||
for (const char *search = this->filter_editbox.text.buf; *search != '\0'; search++) {
|
||||
@@ -377,10 +379,9 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
|
||||
/* Escape special chars, such as &%,= */
|
||||
if (*search < 0x30) {
|
||||
pos += seprintf(pos, last, "%%%02X", *search);
|
||||
} else if (pos < last) {
|
||||
*pos = *search;
|
||||
*++pos = '\0';
|
||||
fmt::format_to(std::back_inserter(url), "%{:02X}", *search);
|
||||
} else {
|
||||
url.push_back(*search);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -424,14 +425,14 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
this->content.RebuildDone();
|
||||
this->SortContentList();
|
||||
|
||||
this->vscroll->SetCount((int)this->content.size()); // Update the scrollbar
|
||||
this->vscroll->SetCount(this->content.size()); // Update the scrollbar
|
||||
this->ScrollToSelected();
|
||||
}
|
||||
|
||||
/** Sort content by name. */
|
||||
static bool NameSorter(const ContentInfo * const &a, const ContentInfo * const &b)
|
||||
{
|
||||
return strnatcmp(a->name.c_str(), b->name.c_str(), true) < 0; // Sort by name (natural sorting).
|
||||
return StrNaturalCompare(a->name, b->name, true) < 0; // Sort by name (natural sorting).
|
||||
}
|
||||
|
||||
/** Sort content by type. */
|
||||
@@ -439,7 +440,7 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
{
|
||||
int r = 0;
|
||||
if (a->type != b->type) {
|
||||
r = strnatcmp(content_type_strs[a->type], content_type_strs[b->type]);
|
||||
r = StrNaturalCompare(content_type_strs[a->type], content_type_strs[b->type]);
|
||||
}
|
||||
if (r == 0) return NameSorter(a, b);
|
||||
return r < 0;
|
||||
@@ -466,9 +467,9 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
static bool CDECL TagNameFilter(const ContentInfo * const *a, ContentListFilterData &filter)
|
||||
{
|
||||
filter.string_filter.ResetState();
|
||||
for (auto &tag : (*a)->tags) filter.string_filter.AddLine(tag.c_str());
|
||||
for (auto &tag : (*a)->tags) filter.string_filter.AddLine(tag);
|
||||
|
||||
filter.string_filter.AddLine((*a)->name.c_str());
|
||||
filter.string_filter.AddLine((*a)->name);
|
||||
return filter.string_filter.GetState();
|
||||
}
|
||||
|
||||
@@ -571,7 +572,7 @@ public:
|
||||
this->InvalidateData();
|
||||
}
|
||||
|
||||
void Close() override
|
||||
void Close([[maybe_unused]] int data = 0) override
|
||||
{
|
||||
_network_content_client.RemoveCallback(this);
|
||||
this->Window::Close();
|
||||
@@ -582,7 +583,7 @@ public:
|
||||
this->checkbox_size = maxdim(maxdim(GetSpriteSize(SPR_BOX_EMPTY), GetSpriteSize(SPR_BOX_CHECKED)), GetSpriteSize(SPR_BLOT));
|
||||
}
|
||||
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_NCL_CHECKBOX:
|
||||
@@ -599,14 +600,14 @@ public:
|
||||
}
|
||||
|
||||
case WID_NCL_MATRIX:
|
||||
resize->height = std::max(this->checkbox_size.height, (uint)FONT_HEIGHT_NORMAL) + padding.height;
|
||||
resize->height = std::max(this->checkbox_size.height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
|
||||
size->height = 10 * resize->height;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
void DrawWidget(const Rect &r, WidgetID widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_NCL_DETAILS:
|
||||
@@ -648,7 +649,7 @@ public:
|
||||
|
||||
/* Fill the matrix with the information */
|
||||
int sprite_y_offset = (this->resize.step_height - this->checkbox_size.height) / 2;
|
||||
int text_y_offset = (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2;
|
||||
int text_y_offset = (this->resize.step_height - GetCharacterHeight(FS_NORMAL)) / 2;
|
||||
|
||||
Rect mr = r.WithHeight(this->resize.step_height);
|
||||
auto iter = this->content.begin() + this->vscroll->GetPosition();
|
||||
@@ -687,7 +688,7 @@ public:
|
||||
void DrawDetails(const Rect &r) const
|
||||
{
|
||||
/* Height for the title banner */
|
||||
int HEADER_HEIGHT = 3 * FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.frametext.Vertical();
|
||||
int HEADER_HEIGHT = 3 * GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.frametext.Vertical();
|
||||
|
||||
Rect hr = r.WithHeight(HEADER_HEIGHT).Shrink(WidgetDimensions::scaled.frametext);
|
||||
Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
|
||||
@@ -699,15 +700,15 @@ public:
|
||||
|
||||
/* Draw the total download size */
|
||||
SetDParam(0, this->filesize_sum);
|
||||
DrawString(tr.left, tr.right, tr.bottom - FONT_HEIGHT_NORMAL + 1, STR_CONTENT_TOTAL_DOWNLOAD_SIZE);
|
||||
DrawString(tr.left, tr.right, tr.bottom - GetCharacterHeight(FS_NORMAL) + 1, STR_CONTENT_TOTAL_DOWNLOAD_SIZE);
|
||||
|
||||
if (this->selected == nullptr) return;
|
||||
|
||||
/* And fill the rest of the details when there's information to place there */
|
||||
DrawStringMultiLine(hr.left, hr.right, hr.top + FONT_HEIGHT_NORMAL, hr.bottom, STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED + this->selected->state, TC_FROMSTRING, SA_CENTER);
|
||||
DrawStringMultiLine(hr.left, hr.right, hr.top + GetCharacterHeight(FS_NORMAL), hr.bottom, STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED + this->selected->state, TC_FROMSTRING, SA_CENTER);
|
||||
|
||||
/* Also show the total download size, so keep some space from the bottom */
|
||||
tr.bottom -= FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_wide;
|
||||
tr.bottom -= GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_wide;
|
||||
|
||||
if (this->selected->upgrade) {
|
||||
SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
|
||||
@@ -742,8 +743,7 @@ public:
|
||||
|
||||
if (!this->selected->dependencies.empty()) {
|
||||
/* List dependencies */
|
||||
char buf[DRAW_STRING_BUFFER] = "";
|
||||
char *p = buf;
|
||||
std::string buf;
|
||||
for (auto &cid : this->selected->dependencies) {
|
||||
/* Try to find the dependency */
|
||||
ConstContentIterator iter = _network_content_client.Begin();
|
||||
@@ -751,7 +751,8 @@ public:
|
||||
const ContentInfo *ci = *iter;
|
||||
if (ci->id != cid) continue;
|
||||
|
||||
p += seprintf(p, lastof(buf), p == buf ? "%s" : ", %s", (*iter)->name.c_str());
|
||||
if (!buf.empty()) buf += ", ";
|
||||
buf += (*iter)->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -761,10 +762,10 @@ public:
|
||||
|
||||
if (!this->selected->tags.empty()) {
|
||||
/* List all tags */
|
||||
char buf[DRAW_STRING_BUFFER] = "";
|
||||
char *p = buf;
|
||||
std::string buf;
|
||||
for (auto &tag : this->selected->tags) {
|
||||
p += seprintf(p, lastof(buf), p == buf ? "%s" : ", %s", tag.c_str());
|
||||
if (!buf.empty()) buf += ", ";
|
||||
buf += tag;
|
||||
}
|
||||
SetDParamStr(0, buf);
|
||||
tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_TAGS);
|
||||
@@ -775,23 +776,23 @@ public:
|
||||
ConstContentVector tree;
|
||||
_network_content_client.ReverseLookupTreeDependency(tree, this->selected);
|
||||
|
||||
char buf[DRAW_STRING_BUFFER] = "";
|
||||
char *p = buf;
|
||||
std::string buf;
|
||||
for (const ContentInfo *ci : tree) {
|
||||
if (ci == this->selected || ci->state != ContentInfo::SELECTED) continue;
|
||||
|
||||
p += seprintf(p, lastof(buf), buf == p ? "%s" : ", %s", ci->name.c_str());
|
||||
if (!buf.empty()) buf += ", ";
|
||||
buf += ci->name;
|
||||
}
|
||||
if (p != buf) {
|
||||
if (!buf.empty()) {
|
||||
SetDParamStr(0, buf);
|
||||
tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
|
||||
{
|
||||
if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_END) {
|
||||
if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_CONTENT_END) {
|
||||
if (this->selected == nullptr || this->selected->state != ContentInfo::ALREADY_HERE) return;
|
||||
|
||||
ShowContentTextfileWindow((TextfileType)(widget - WID_NCL_TEXTFILE), this->selected);
|
||||
@@ -800,11 +801,11 @@ public:
|
||||
|
||||
switch (widget) {
|
||||
case WID_NCL_MATRIX: {
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NCL_MATRIX);
|
||||
if (id_v >= this->content.size()) return; // click out of bounds
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->content, pt.y, this, WID_NCL_MATRIX);
|
||||
if (it == this->content.end()) return; // click out of bounds
|
||||
|
||||
this->selected = this->content[id_v];
|
||||
this->list_pos = id_v;
|
||||
this->selected = *it;
|
||||
this->list_pos = it - this->content.begin();
|
||||
|
||||
const NWidgetBase *checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX);
|
||||
if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) {
|
||||
@@ -825,7 +826,7 @@ public:
|
||||
case WID_NCL_NAME:
|
||||
if (this->content.SortType() == widget - WID_NCL_CHECKBOX) {
|
||||
this->content.ToggleSortOrder();
|
||||
if (this->content.size() > 0) this->list_pos = (int)this->content.size() - this->list_pos - 1;
|
||||
if (!this->content.empty()) this->list_pos = (int)this->content.size() - this->list_pos - 1;
|
||||
} else {
|
||||
this->content.SetSortType(widget - WID_NCL_CHECKBOX);
|
||||
this->content.ForceResort();
|
||||
@@ -856,8 +857,7 @@ public:
|
||||
|
||||
case WID_NCL_OPEN_URL:
|
||||
if (this->selected != nullptr) {
|
||||
extern void OpenBrowser(const char *url);
|
||||
OpenBrowser(this->selected->url.c_str());
|
||||
OpenBrowser(this->selected->url);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -875,7 +875,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
EventState OnKeyPress(WChar key, uint16 keycode) override
|
||||
EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
|
||||
{
|
||||
if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_NOT_HANDLED) {
|
||||
switch (keycode) {
|
||||
@@ -894,14 +894,14 @@ public:
|
||||
return ES_HANDLED;
|
||||
}
|
||||
/* space is pressed and filter is focused. */
|
||||
FALLTHROUGH;
|
||||
[[fallthrough]];
|
||||
|
||||
default:
|
||||
return ES_NOT_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->content.size() == 0) {
|
||||
if (this->content.empty()) {
|
||||
if (this->UpdateFilterState()) {
|
||||
this->content.ForceRebuild();
|
||||
this->InvalidateData();
|
||||
@@ -923,7 +923,7 @@ public:
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
void OnEditboxChanged(int wid) override
|
||||
void OnEditboxChanged(WidgetID wid) override
|
||||
{
|
||||
if (wid == WID_NCL_FILTER) {
|
||||
this->filter_data.string_filter.SetFilterTerm(this->filter_editbox.text.buf);
|
||||
@@ -945,7 +945,7 @@ public:
|
||||
this->InvalidateData(0, false);
|
||||
}
|
||||
|
||||
void OnDownloadComplete(ContentID cid) override
|
||||
void OnDownloadComplete(ContentID) override
|
||||
{
|
||||
this->content.ForceResort();
|
||||
this->InvalidateData();
|
||||
@@ -967,7 +967,7 @@ public:
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
|
||||
{
|
||||
if (!gui_scope) return;
|
||||
if (this->content.NeedRebuild()) this->BuildContentList();
|
||||
@@ -999,8 +999,8 @@ public:
|
||||
this->SetWidgetDisabledState(WID_NCL_SELECT_ALL, !show_select_all);
|
||||
this->SetWidgetDisabledState(WID_NCL_SELECT_UPDATE, !show_select_upgrade);
|
||||
this->SetWidgetDisabledState(WID_NCL_OPEN_URL, this->selected == nullptr || this->selected->url.empty());
|
||||
for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) {
|
||||
this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == nullptr || this->selected->state != ContentInfo::ALREADY_HERE || this->selected->GetTextfile(tft) == nullptr);
|
||||
for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {
|
||||
this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == nullptr || this->selected->state != ContentInfo::ALREADY_HERE || !this->selected->GetTextfile(tft).has_value());
|
||||
}
|
||||
|
||||
this->GetWidget<NWidgetCore>(WID_NCL_CANCEL)->widget_data = this->filesize_sum == 0 ? STR_AI_SETTINGS_CLOSE : STR_AI_LIST_CANCEL;
|
||||
@@ -1021,7 +1021,7 @@ NetworkContentListWindow::GUIContentList::FilterFunction * const NetworkContentL
|
||||
&TypeOrSelectedFilter,
|
||||
};
|
||||
|
||||
char NetworkContentListWindow::content_type_strs[CONTENT_TYPE_END][64];
|
||||
std::string NetworkContentListWindow::content_type_strs[CONTENT_TYPE_END];
|
||||
|
||||
/**
|
||||
* Build array of all strings corresponding to the content types.
|
||||
@@ -1029,87 +1029,95 @@ char NetworkContentListWindow::content_type_strs[CONTENT_TYPE_END][64];
|
||||
void BuildContentTypeStringList()
|
||||
{
|
||||
for (int i = CONTENT_TYPE_BEGIN; i < CONTENT_TYPE_END; i++) {
|
||||
GetString(NetworkContentListWindow::content_type_strs[i], STR_CONTENT_TYPE_BASE_GRAPHICS + i - CONTENT_TYPE_BASE_GRAPHICS, lastof(NetworkContentListWindow::content_type_strs[i]));
|
||||
NetworkContentListWindow::content_type_strs[i] = GetString(STR_CONTENT_TYPE_BASE_GRAPHICS + i - CONTENT_TYPE_BASE_GRAPHICS);
|
||||
}
|
||||
}
|
||||
|
||||
/** The widgets for the content list. */
|
||||
static const NWidgetPart _nested_network_content_list_widgets[] = {
|
||||
static constexpr NWidgetPart _nested_network_content_list_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
|
||||
NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_CONTENT_TITLE, STR_NULL),
|
||||
NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_BACKGROUND),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(0, 3), SetResize(1, 0),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
|
||||
/* Left side. */
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, 4, 0),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CHECKBOX), SetMinimalSize(13, 1), SetDataTip(STR_EMPTY, STR_NULL),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TYPE),
|
||||
SetDataTip(STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_NAME), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TOOLTIP),
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0), SetPadding(WidgetDimensions::unscaled.sparse_resize),
|
||||
/* Top */
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0),
|
||||
NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NCL_FILTER_CAPT), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_CONTENT_FILTER_TITLE, STR_NULL), SetAlignment(SA_RIGHT | SA_VERT_CENTER),
|
||||
NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NCL_FILTER), SetFill(1, 0), SetResize(1, 0),
|
||||
SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
|
||||
EndContainer(),
|
||||
/* Lists and info. */
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0),
|
||||
/* Left side. */
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_sparse, 0),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CHECKBOX), SetMinimalSize(13, 1), SetDataTip(STR_EMPTY, STR_NULL),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TYPE),
|
||||
SetDataTip(STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_NAME), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NCL_MATRIX), SetResize(1, 14), SetFill(1, 1), SetScrollbar(WID_NCL_SCROLLBAR), SetMatrixDataTip(1, 0, STR_CONTENT_MATRIX_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NCL_MATRIX), SetResize(1, 14), SetFill(1, 1), SetScrollbar(WID_NCL_SCROLLBAR), SetMatrixDataTip(1, 0, STR_CONTENT_MATRIX_TOOLTIP),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NCL_SCROLLBAR),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0),
|
||||
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NCL_SEL_ALL_UPDATE),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_UPDATE), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_ALL), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_UNSELECT), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NCL_SCROLLBAR),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0),
|
||||
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NCL_SEL_ALL_UPDATE), SetResize(1, 0), SetFill(1, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_UPDATE), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_ALL), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP),
|
||||
/* Right side. */
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_sparse, 0),
|
||||
NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_DETAILS), SetResize(1, 1), SetFill(1, 1),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_OPEN_URL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_UNSELECT), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
/* Right side. */
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, 4, 0),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
|
||||
/* Top */
|
||||
NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NCL_FILTER_CAPT), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_CONTENT_FILTER_TITLE, STR_NULL), SetAlignment(SA_RIGHT),
|
||||
NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NCL_FILTER), SetFill(1, 0), SetResize(1, 0),
|
||||
SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(0, 3), SetResize(1, 0),
|
||||
NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_DETAILS), SetResize(1, 1), SetFill(1, 1), EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_OPEN_URL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL),
|
||||
/* Bottom. */
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SEARCH_EXTERNAL), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_SEARCH_EXTERNAL, STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CANCEL), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_DOWNLOAD), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0),
|
||||
/* Bottom. */
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SEARCH_EXTERNAL), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_SEARCH_EXTERNAL, STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_DOWNLOAD), SetResize(1, 0), SetFill(1, 0),
|
||||
SetDataTip(STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP),
|
||||
/* Resize button. */
|
||||
NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE),
|
||||
EndContainer(),
|
||||
/* Resize button. */
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
|
||||
NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE), SetDataTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
/** Window description of the content list */
|
||||
static WindowDesc _network_content_list_desc(
|
||||
static WindowDesc _network_content_list_desc(__FILE__, __LINE__,
|
||||
WDP_CENTER, "list_content", 630, 460,
|
||||
WC_NETWORK_WINDOW, WC_NONE,
|
||||
0,
|
||||
_nested_network_content_list_widgets, lengthof(_nested_network_content_list_widgets)
|
||||
std::begin(_nested_network_content_list_widgets), std::end(_nested_network_content_list_widgets)
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ protected:
|
||||
uint total_files; ///< Number of files to download
|
||||
uint downloaded_files; ///< Number of files downloaded
|
||||
|
||||
uint32 cur_id; ///< The current ID of the downloaded file
|
||||
uint32_t cur_id; ///< The current ID of the downloaded file
|
||||
std::string name; ///< The current name of the downloaded file
|
||||
|
||||
public:
|
||||
@@ -32,9 +32,9 @@ public:
|
||||
*/
|
||||
BaseNetworkContentDownloadStatusWindow(WindowDesc *desc);
|
||||
|
||||
void Close() override;
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override;
|
||||
void DrawWidget(const Rect &r, int widget) const override;
|
||||
void Close([[maybe_unused]] int data = 0) override;
|
||||
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override;
|
||||
void DrawWidget(const Rect &r, WidgetID widget) const override;
|
||||
void OnDownloadProgress(const ContentInfo *ci, int bytes) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ std::string _network_server_invite_code = ""; ///< Our invite code as indicated
|
||||
class NetworkDirectConnecter : public TCPConnecter {
|
||||
private:
|
||||
std::string token; ///< Token of this connection.
|
||||
uint8 tracking_number; ///< Tracking number of this connection.
|
||||
uint8_t tracking_number; ///< Tracking number of this connection.
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
* @param token The token as given by the Game Coordinator to track this connection attempt.
|
||||
* @param tracking_number The tracking number as given by the Game Coordinator to track this connection attempt.
|
||||
*/
|
||||
NetworkDirectConnecter(const std::string &hostname, uint16 port, const std::string &token, uint8 tracking_number) : TCPConnecter(hostname, port), token(token), tracking_number(tracking_number) {}
|
||||
NetworkDirectConnecter(const std::string &hostname, uint16_t port, const std::string &token, uint8_t tracking_number) : TCPConnecter(hostname, port), token(token), tracking_number(tracking_number) {}
|
||||
|
||||
void OnFailure() override
|
||||
{
|
||||
@@ -63,8 +63,8 @@ public:
|
||||
class NetworkReuseStunConnecter : public TCPConnecter {
|
||||
private:
|
||||
std::string token; ///< Token of this connection.
|
||||
uint8 tracking_number; ///< Tracking number of this connection.
|
||||
uint8 family; ///< Family of this connection.
|
||||
uint8_t tracking_number; ///< Tracking number of this connection.
|
||||
uint8_t family; ///< Family of this connection.
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
* @param tracking_number The tracking number of the connection.
|
||||
* @param family The family this connection is using.
|
||||
*/
|
||||
NetworkReuseStunConnecter(const std::string &hostname, uint16 port, const NetworkAddress &bind_address, std::string token, uint8 tracking_number, uint8 family) :
|
||||
NetworkReuseStunConnecter(const std::string &hostname, uint16_t port, const NetworkAddress &bind_address, std::string token, uint8_t tracking_number, uint8_t family) :
|
||||
TCPConnecter(hostname, port, bind_address),
|
||||
token(token),
|
||||
tracking_number(tracking_number),
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
};
|
||||
|
||||
/** Connect to the Game Coordinator server. */
|
||||
class NetworkCoordinatorConnecter : TCPConnecter {
|
||||
class NetworkCoordinatorConnecter : public TCPConnecter {
|
||||
public:
|
||||
/**
|
||||
* Initiate the connecting.
|
||||
@@ -124,10 +124,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet *p)
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet &p)
|
||||
{
|
||||
NetworkCoordinatorErrorType error = (NetworkCoordinatorErrorType)p->Recv_uint8();
|
||||
std::string detail = p->Recv_string(NETWORK_ERROR_DETAIL_LENGTH);
|
||||
NetworkCoordinatorErrorType error = (NetworkCoordinatorErrorType)p.Recv_uint8();
|
||||
std::string detail = p.Recv_string(NETWORK_ERROR_DETAIL_LENGTH);
|
||||
|
||||
switch (error) {
|
||||
case NETWORK_COORDINATOR_ERROR_UNKNOWN:
|
||||
@@ -174,14 +174,14 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet *p)
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet *p)
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet &p)
|
||||
{
|
||||
/* Schedule sending an update. */
|
||||
this->next_update = std::chrono::steady_clock::now();
|
||||
|
||||
_settings_client.network.server_invite_code = p->Recv_string(NETWORK_INVITE_CODE_LENGTH);
|
||||
_settings_client.network.server_invite_code_secret = p->Recv_string(NETWORK_INVITE_CODE_SECRET_LENGTH);
|
||||
_network_server_connection_type = (ConnectionType)p->Recv_uint8();
|
||||
_settings_client.network.server_invite_code = p.Recv_string(NETWORK_INVITE_CODE_LENGTH);
|
||||
_settings_client.network.server_invite_code_secret = p.Recv_string(NETWORK_INVITE_CODE_SECRET_LENGTH);
|
||||
_network_server_connection_type = (ConnectionType)p.Recv_uint8();
|
||||
|
||||
if (_network_server_connection_type == CONNECTION_TYPE_ISOLATED) {
|
||||
ShowErrorMessage(STR_NETWORK_ERROR_COORDINATOR_ISOLATED, STR_NETWORK_ERROR_COORDINATOR_ISOLATED_DETAIL, WL_ERROR);
|
||||
@@ -230,9 +230,9 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet *p)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p)
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet &p)
|
||||
{
|
||||
uint8 servers = p->Recv_uint16();
|
||||
uint8_t servers = p.Recv_uint16();
|
||||
|
||||
/* End of list; we can now remove all expired items from the list. */
|
||||
if (servers == 0) {
|
||||
@@ -241,11 +241,11 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p)
|
||||
}
|
||||
|
||||
for (; servers > 0; servers--) {
|
||||
std::string connection_string = p->Recv_string(NETWORK_HOSTNAME_PORT_LENGTH);
|
||||
std::string connection_string = p.Recv_string(NETWORK_HOSTNAME_PORT_LENGTH);
|
||||
|
||||
/* Read the NetworkGameInfo from the packet. */
|
||||
NetworkGameInfo ngi = {};
|
||||
DeserializeNetworkGameInfo(p, &ngi, &this->newgrf_lookup_table);
|
||||
DeserializeNetworkGameInfo(p, ngi, &this->newgrf_lookup_table);
|
||||
|
||||
/* Now we know the connection string, we can add it to our list. */
|
||||
NetworkGameList *item = NetworkGameListAddItem(connection_string);
|
||||
@@ -266,10 +266,10 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_CONNECTING(Packet *p)
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_CONNECTING(Packet &p)
|
||||
{
|
||||
std::string token = p->Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
std::string invite_code = p->Recv_string(NETWORK_INVITE_CODE_LENGTH);
|
||||
std::string token = p.Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
std::string invite_code = p.Recv_string(NETWORK_INVITE_CODE_LENGTH);
|
||||
|
||||
/* Find the connecter based on the invite code. */
|
||||
auto connecter_pre_it = this->connecter_pre.find(invite_code);
|
||||
@@ -285,20 +285,20 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_CONNECTING(Packet *p)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_CONNECT_FAILED(Packet *p)
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_CONNECT_FAILED(Packet &p)
|
||||
{
|
||||
std::string token = p->Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
std::string token = p.Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
this->CloseToken(token);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_DIRECT_CONNECT(Packet *p)
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_DIRECT_CONNECT(Packet &p)
|
||||
{
|
||||
std::string token = p->Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
uint8 tracking_number = p->Recv_uint8();
|
||||
std::string hostname = p->Recv_string(NETWORK_HOSTNAME_LENGTH);
|
||||
uint16 port = p->Recv_uint16();
|
||||
std::string token = p.Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
uint8_t tracking_number = p.Recv_uint8();
|
||||
std::string hostname = p.Recv_string(NETWORK_HOSTNAME_LENGTH);
|
||||
uint16_t port = p.Recv_uint16();
|
||||
|
||||
/* Ensure all other pending connection attempts are killed. */
|
||||
if (this->game_connecter != nullptr) {
|
||||
@@ -306,26 +306,26 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_DIRECT_CONNECT(Packet *p)
|
||||
this->game_connecter = nullptr;
|
||||
}
|
||||
|
||||
this->game_connecter = new NetworkDirectConnecter(hostname, port, token, tracking_number);
|
||||
this->game_connecter = TCPConnecter::Create<NetworkDirectConnecter>(hostname, port, token, tracking_number);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_STUN_REQUEST(Packet *p)
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_STUN_REQUEST(Packet &p)
|
||||
{
|
||||
std::string token = p->Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
std::string token = p.Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
|
||||
this->stun_handlers[token][AF_INET6] = ClientNetworkStunSocketHandler::Stun(token, AF_INET6);
|
||||
this->stun_handlers[token][AF_INET] = ClientNetworkStunSocketHandler::Stun(token, AF_INET);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_STUN_CONNECT(Packet *p)
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_STUN_CONNECT(Packet &p)
|
||||
{
|
||||
std::string token = p->Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
uint8 tracking_number = p->Recv_uint8();
|
||||
uint8 family = p->Recv_uint8();
|
||||
std::string host = p->Recv_string(NETWORK_HOSTNAME_PORT_LENGTH);
|
||||
uint16 port = p->Recv_uint16();
|
||||
std::string token = p.Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
uint8_t tracking_number = p.Recv_uint8();
|
||||
uint8_t family = p.Recv_uint8();
|
||||
std::string host = p.Recv_string(NETWORK_HOSTNAME_PORT_LENGTH);
|
||||
uint16_t port = p.Recv_uint16();
|
||||
|
||||
/* Check if we know this token. */
|
||||
auto stun_it = this->stun_handlers.find(token);
|
||||
@@ -349,28 +349,28 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_STUN_CONNECT(Packet *p)
|
||||
* STUN server. This means that if there is any NAT in the local network,
|
||||
* the public ip:port is still pointing to the local address, and as such
|
||||
* a connection can be established. */
|
||||
this->game_connecter = new NetworkReuseStunConnecter(host, port, family_it->second->local_addr, token, tracking_number, family);
|
||||
this->game_connecter = TCPConnecter::Create<NetworkReuseStunConnecter>(host, port, family_it->second->local_addr, token, tracking_number, family);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_NEWGRF_LOOKUP(Packet *p)
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_NEWGRF_LOOKUP(Packet &p)
|
||||
{
|
||||
this->newgrf_lookup_table_cursor = p->Recv_uint32();
|
||||
this->newgrf_lookup_table_cursor = p.Recv_uint32();
|
||||
|
||||
uint16 newgrfs = p->Recv_uint16();
|
||||
uint16_t newgrfs = p.Recv_uint16();
|
||||
for (; newgrfs> 0; newgrfs--) {
|
||||
uint32 index = p->Recv_uint32();
|
||||
DeserializeGRFIdentifierWithName(p, &this->newgrf_lookup_table[index]);
|
||||
uint32_t index = p.Recv_uint32();
|
||||
DeserializeGRFIdentifierWithName(p, this->newgrf_lookup_table[index]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_TURN_CONNECT(Packet *p)
|
||||
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_TURN_CONNECT(Packet &p)
|
||||
{
|
||||
std::string token = p->Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
uint8 tracking_number = p->Recv_uint8();
|
||||
std::string ticket = p->Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
std::string connection_string = p->Recv_string(NETWORK_HOSTNAME_PORT_LENGTH);
|
||||
std::string token = p.Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
uint8_t tracking_number = p.Recv_uint8();
|
||||
std::string ticket = p.Recv_string(NETWORK_TOKEN_LENGTH);
|
||||
std::string connection_string = p.Recv_string(NETWORK_HOSTNAME_PORT_LENGTH);
|
||||
|
||||
/* Ensure all other pending connection attempts are killed. */
|
||||
if (this->game_connecter != nullptr) {
|
||||
@@ -426,7 +426,7 @@ void ClientNetworkCoordinatorSocketHandler::Connect()
|
||||
this->connecting = true;
|
||||
this->last_activity = std::chrono::steady_clock::now();
|
||||
|
||||
new NetworkCoordinatorConnecter(NetworkCoordinatorConnectionString());
|
||||
TCPConnecter::Create<NetworkCoordinatorConnecter>(NetworkCoordinatorConnectionString());
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkCoordinatorSocketHandler::CloseConnection(bool error)
|
||||
@@ -458,7 +458,7 @@ void ClientNetworkCoordinatorSocketHandler::Register()
|
||||
|
||||
this->Connect();
|
||||
|
||||
Packet *p = new Packet(PACKET_COORDINATOR_SERVER_REGISTER);
|
||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_SERVER_REGISTER);
|
||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||
p->Send_uint8(_settings_client.network.server_game_type);
|
||||
p->Send_uint16(_settings_client.network.server_port);
|
||||
@@ -470,7 +470,7 @@ void ClientNetworkCoordinatorSocketHandler::Register()
|
||||
p->Send_string(_settings_client.network.server_invite_code_secret);
|
||||
}
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -480,11 +480,11 @@ void ClientNetworkCoordinatorSocketHandler::SendServerUpdate()
|
||||
{
|
||||
Debug(net, 6, "Sending server update to Game Coordinator");
|
||||
|
||||
Packet *p = new Packet(PACKET_COORDINATOR_SERVER_UPDATE, TCP_MTU);
|
||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_SERVER_UPDATE, TCP_MTU);
|
||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||
SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo(), this->next_update.time_since_epoch() != std::chrono::nanoseconds::zero());
|
||||
SerializeNetworkGameInfo(*p, GetCurrentNetworkServerGameInfo(), this->next_update.time_since_epoch() != std::chrono::nanoseconds::zero());
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
this->next_update = std::chrono::steady_clock::now() + NETWORK_COORDINATOR_DELAY_BETWEEN_UPDATES;
|
||||
}
|
||||
@@ -498,13 +498,13 @@ void ClientNetworkCoordinatorSocketHandler::GetListing()
|
||||
|
||||
_network_game_list_version++;
|
||||
|
||||
Packet *p = new Packet(PACKET_COORDINATOR_CLIENT_LISTING);
|
||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_CLIENT_LISTING);
|
||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||
p->Send_uint8(NETWORK_GAME_INFO_VERSION);
|
||||
p->Send_string(_openttd_revision);
|
||||
p->Send_uint32(this->newgrf_lookup_table_cursor);
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -514,7 +514,7 @@ void ClientNetworkCoordinatorSocketHandler::GetListing()
|
||||
*/
|
||||
void ClientNetworkCoordinatorSocketHandler::ConnectToServer(const std::string &invite_code, TCPServerConnecter *connecter)
|
||||
{
|
||||
assert(StrStartsWith(invite_code, "+"));
|
||||
assert(invite_code.starts_with("+"));
|
||||
|
||||
if (this->connecter_pre.find(invite_code) != this->connecter_pre.end()) {
|
||||
/* If someone is hammering the refresh key, one can sent out two
|
||||
@@ -530,11 +530,11 @@ void ClientNetworkCoordinatorSocketHandler::ConnectToServer(const std::string &i
|
||||
|
||||
this->Connect();
|
||||
|
||||
Packet *p = new Packet(PACKET_COORDINATOR_CLIENT_CONNECT);
|
||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_CLIENT_CONNECT);
|
||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||
p->Send_string(invite_code);
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -542,17 +542,17 @@ void ClientNetworkCoordinatorSocketHandler::ConnectToServer(const std::string &i
|
||||
* @param token Token of the connecter that failed.
|
||||
* @param tracking_number Tracking number of the connecter that failed.
|
||||
*/
|
||||
void ClientNetworkCoordinatorSocketHandler::ConnectFailure(const std::string &token, uint8 tracking_number)
|
||||
void ClientNetworkCoordinatorSocketHandler::ConnectFailure(const std::string &token, uint8_t tracking_number)
|
||||
{
|
||||
/* Connecter will destroy itself. */
|
||||
this->game_connecter = nullptr;
|
||||
|
||||
Packet *p = new Packet(PACKET_COORDINATOR_SERCLI_CONNECT_FAILED);
|
||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_SERCLI_CONNECT_FAILED);
|
||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||
p->Send_string(token);
|
||||
p->Send_uint8(tracking_number);
|
||||
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
/* We do not close the associated connecter here yet, as the
|
||||
* Game Coordinator might have other methods of connecting available. */
|
||||
@@ -578,10 +578,10 @@ void ClientNetworkCoordinatorSocketHandler::ConnectSuccess(const std::string &to
|
||||
} else {
|
||||
/* The client informs the Game Coordinator about the success. The server
|
||||
* doesn't have to, as it is implied by the client telling. */
|
||||
Packet *p = new Packet(PACKET_COORDINATOR_CLIENT_CONNECTED);
|
||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_CLIENT_CONNECTED);
|
||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||
p->Send_string(token);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
/* Find the connecter; it can happen it no longer exist, in cases where
|
||||
* we aborted the connect but the Game Coordinator was already in the
|
||||
@@ -604,14 +604,14 @@ void ClientNetworkCoordinatorSocketHandler::ConnectSuccess(const std::string &to
|
||||
* This helps the Game Coordinator not to wait for a timeout on its end, but
|
||||
* rather react as soon as the client/server knows the result.
|
||||
*/
|
||||
void ClientNetworkCoordinatorSocketHandler::StunResult(const std::string &token, uint8 family, bool result)
|
||||
void ClientNetworkCoordinatorSocketHandler::StunResult(const std::string &token, uint8_t family, bool result)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_COORDINATOR_SERCLI_STUN_RESULT);
|
||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_SERCLI_STUN_RESULT);
|
||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||
p->Send_string(token);
|
||||
p->Send_uint8(family);
|
||||
p->Send_bool(result);
|
||||
this->SendPacket(p);
|
||||
this->SendPacket(std::move(p));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -619,7 +619,7 @@ void ClientNetworkCoordinatorSocketHandler::StunResult(const std::string &token,
|
||||
* @param token The token used for the STUN handlers.
|
||||
* @param family The family of STUN handlers to close. AF_UNSPEC to close all STUN handlers for this token.
|
||||
*/
|
||||
void ClientNetworkCoordinatorSocketHandler::CloseStunHandler(const std::string &token, uint8 family)
|
||||
void ClientNetworkCoordinatorSocketHandler::CloseStunHandler(const std::string &token, uint8_t family)
|
||||
{
|
||||
auto stun_it = this->stun_handlers.find(token);
|
||||
if (stun_it == this->stun_handlers.end()) return;
|
||||
@@ -648,7 +648,7 @@ void ClientNetworkCoordinatorSocketHandler::CloseStunHandler(const std::string &
|
||||
*/
|
||||
void ClientNetworkCoordinatorSocketHandler::CloseTurnHandler(const std::string &token)
|
||||
{
|
||||
CloseWindowByClass(WC_NETWORK_ASK_RELAY);
|
||||
CloseWindowByClass(WC_NETWORK_ASK_RELAY, NRWCD_HANDLED);
|
||||
|
||||
auto turn_it = this->turn_handlers.find(token);
|
||||
if (turn_it == this->turn_handlers.end()) return;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "core/tcp_coordinator.h"
|
||||
#include "network_stun.h"
|
||||
#include "network_turn.h"
|
||||
#include <map>
|
||||
|
||||
/**
|
||||
* Game Coordinator communication.
|
||||
@@ -58,22 +57,22 @@ private:
|
||||
std::map<std::string, TCPServerConnecter *> connecter_pre; ///< Based on invite codes, the current connecters that are pending.
|
||||
std::map<std::string, std::map<int, std::unique_ptr<ClientNetworkStunSocketHandler>>> stun_handlers; ///< All pending STUN handlers, stored by token:family.
|
||||
std::map<std::string, std::unique_ptr<ClientNetworkTurnSocketHandler>> turn_handlers; ///< Pending TURN handler (if any), stored by token.
|
||||
TCPConnecter *game_connecter = nullptr; ///< Pending connecter to the game server.
|
||||
std::shared_ptr<TCPConnecter> game_connecter{}; ///< Pending connecter to the game server.
|
||||
|
||||
uint32 newgrf_lookup_table_cursor = 0; ///< Last received cursor for the #GameInfoNewGRFLookupTable updates.
|
||||
uint32_t newgrf_lookup_table_cursor = 0; ///< Last received cursor for the #GameInfoNewGRFLookupTable updates.
|
||||
GameInfoNewGRFLookupTable newgrf_lookup_table; ///< Table to look up NewGRFs in the GC_LISTING packets.
|
||||
|
||||
protected:
|
||||
bool Receive_GC_ERROR(Packet *p) override;
|
||||
bool Receive_GC_REGISTER_ACK(Packet *p) override;
|
||||
bool Receive_GC_LISTING(Packet *p) override;
|
||||
bool Receive_GC_CONNECTING(Packet *p) override;
|
||||
bool Receive_GC_CONNECT_FAILED(Packet *p) override;
|
||||
bool Receive_GC_DIRECT_CONNECT(Packet *p) override;
|
||||
bool Receive_GC_STUN_REQUEST(Packet *p) override;
|
||||
bool Receive_GC_STUN_CONNECT(Packet *p) override;
|
||||
bool Receive_GC_NEWGRF_LOOKUP(Packet *p) override;
|
||||
bool Receive_GC_TURN_CONNECT(Packet *p) override;
|
||||
bool Receive_GC_ERROR(Packet &p) override;
|
||||
bool Receive_GC_REGISTER_ACK(Packet &p) override;
|
||||
bool Receive_GC_LISTING(Packet &p) override;
|
||||
bool Receive_GC_CONNECTING(Packet &p) override;
|
||||
bool Receive_GC_CONNECT_FAILED(Packet &p) override;
|
||||
bool Receive_GC_DIRECT_CONNECT(Packet &p) override;
|
||||
bool Receive_GC_STUN_REQUEST(Packet &p) override;
|
||||
bool Receive_GC_STUN_CONNECT(Packet &p) override;
|
||||
bool Receive_GC_NEWGRF_LOOKUP(Packet &p) override;
|
||||
bool Receive_GC_TURN_CONNECT(Packet &p) override;
|
||||
|
||||
public:
|
||||
/** The idle timeout; when to close the connection because it's idle. */
|
||||
@@ -87,14 +86,14 @@ public:
|
||||
NetworkRecvStatus CloseConnection(bool error = true) override;
|
||||
void SendReceive();
|
||||
|
||||
void ConnectFailure(const std::string &token, uint8 tracking_number);
|
||||
void ConnectFailure(const std::string &token, uint8_t tracking_number);
|
||||
void ConnectSuccess(const std::string &token, SOCKET sock, NetworkAddress &address);
|
||||
void StunResult(const std::string &token, uint8 family, bool result);
|
||||
void StunResult(const std::string &token, uint8_t family, bool result);
|
||||
|
||||
void Connect();
|
||||
void CloseToken(const std::string &token);
|
||||
void CloseAllConnections();
|
||||
void CloseStunHandler(const std::string &token, uint8 family = AF_UNSPEC);
|
||||
void CloseStunHandler(const std::string &token, uint8_t family = AF_UNSPEC);
|
||||
void CloseTurnHandler(const std::string &token);
|
||||
|
||||
void Register();
|
||||
|
||||
@@ -28,7 +28,7 @@ extern NetworkCompanyState *_network_company_states;
|
||||
|
||||
extern ClientID _network_own_client_id;
|
||||
extern ClientID _redirect_console_to_client;
|
||||
extern uint8 _network_reconnect;
|
||||
extern uint8_t _network_reconnect;
|
||||
extern StringList _network_bind_list;
|
||||
extern StringList _network_host_list;
|
||||
extern StringList _network_ban_list;
|
||||
@@ -43,11 +43,10 @@ void NetworkUpdateServerGameType();
|
||||
bool NetworkCompanyHasClients(CompanyID company);
|
||||
std::string NetworkChangeCompanyPassword(CompanyID company_id, std::string password);
|
||||
void NetworkReboot();
|
||||
void NetworkDisconnect(bool blocking = false, bool close_admins = true);
|
||||
void NetworkDisconnect(bool close_admins = true);
|
||||
void NetworkGameLoop();
|
||||
void NetworkBackgroundLoop();
|
||||
std::string_view ParseFullConnectionString(const std::string &connection_string, uint16 &port, CompanyID *company_id = nullptr);
|
||||
void NetworkStartDebugLog(const std::string &connection_string);
|
||||
std::string_view ParseFullConnectionString(const std::string &connection_string, uint16_t &port, CompanyID *company_id = nullptr);
|
||||
void NetworkPopulateCompanyStats(NetworkCompanyStats *stats);
|
||||
|
||||
void NetworkUpdateClientInfo(ClientID client_id);
|
||||
@@ -56,17 +55,15 @@ bool NetworkClientConnectGame(const std::string &connection_string, CompanyID de
|
||||
void NetworkClientJoinGame();
|
||||
void NetworkClientRequestMove(CompanyID company, const std::string &pass = "");
|
||||
void NetworkClientSendRcon(const std::string &password, const std::string &command);
|
||||
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64 data = 0);
|
||||
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64_t data = 0);
|
||||
bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio);
|
||||
bool NetworkCompanyIsPassworded(CompanyID company_id);
|
||||
uint NetworkMaxCompaniesAllowed();
|
||||
bool NetworkMaxCompaniesReached();
|
||||
void NetworkPrintClients();
|
||||
void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode);
|
||||
|
||||
/*** Commands ran by the server ***/
|
||||
void NetworkServerDailyLoop();
|
||||
void NetworkServerMonthlyLoop();
|
||||
void NetworkServerYearlyLoop();
|
||||
void NetworkServerSendConfigUpdate();
|
||||
void NetworkServerUpdateGameInfo();
|
||||
void NetworkServerShowStatusToConsole();
|
||||
@@ -77,7 +74,7 @@ bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_na
|
||||
|
||||
void NetworkServerDoMove(ClientID client_id, CompanyID company_id);
|
||||
void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const std::string &string);
|
||||
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, ClientID from_id, int64 data = 0, bool from_admin = false);
|
||||
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, ClientID from_id, int64_t data = 0, bool from_admin = false);
|
||||
void NetworkServerSendExternalChat(const std::string &source, TextColour colour, const std::string &user, const std::string &msg);
|
||||
|
||||
void NetworkServerKickClient(ClientID client_id, const std::string &reason);
|
||||
@@ -85,9 +82,9 @@ uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const std::string &r
|
||||
uint NetworkServerKickOrBanIP(const std::string &ip, bool ban, const std::string &reason);
|
||||
|
||||
void NetworkInitChatMessage();
|
||||
void NetworkReInitChatBoxSize();
|
||||
void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const std::string &message);
|
||||
void NetworkUndrawChatMessage();
|
||||
void NetworkChatMessageLoop();
|
||||
|
||||
void NetworkAfterNewGRFScan();
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ void NetworkAfterNewGRFScan()
|
||||
for (GRFConfig *c = item->info.grfconfig; c != nullptr; c = c->next) {
|
||||
assert(HasBit(c->flags, GCF_COPY));
|
||||
|
||||
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum);
|
||||
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, &c->ident.md5sum);
|
||||
if (f == nullptr) {
|
||||
/* Don't know the GRF (anymore), so mark game incompatible. */
|
||||
c->status = GCS_NOT_FOUND;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#define NETWORK_GAMELIST_H
|
||||
|
||||
#include "core/address.h"
|
||||
#include "core/game_info.h"
|
||||
#include "core/network_game_info.h"
|
||||
#include "network_type.h"
|
||||
|
||||
/** The status a server can be in. */
|
||||
|
||||
+472
-398
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@
|
||||
#define NETWORK_GUI_H
|
||||
|
||||
#include "../company_type.h"
|
||||
#include "../date_type.h"
|
||||
#include "../timer/timer_game_calendar.h"
|
||||
#include "../economy_type.h"
|
||||
#include "../window_type.h"
|
||||
#include "network_type.h"
|
||||
@@ -24,19 +24,24 @@ void ShowNetworkGameWindow();
|
||||
void ShowClientList();
|
||||
void ShowNetworkCompanyPasswordWindow(Window *parent);
|
||||
void ShowNetworkAskRelay(const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token);
|
||||
|
||||
void ShowNetworkAskSurvey();
|
||||
void ShowSurveyResultTextfileWindow();
|
||||
|
||||
/** Company information stored at the client side */
|
||||
struct NetworkCompanyInfo : NetworkCompanyStats {
|
||||
std::string company_name; ///< Company name
|
||||
Year inaugurated_year; ///< What year the company started in
|
||||
TimerGameCalendar::Year inaugurated_year; ///< What year the company started in
|
||||
Money company_value; ///< The company value
|
||||
Money money; ///< The amount of money the company has
|
||||
Money income; ///< How much did the company earn last year
|
||||
uint16 performance; ///< What was his performance last month?
|
||||
uint16_t performance; ///< What was his performance last month?
|
||||
bool use_password; ///< Is there a password
|
||||
std::string clients; ///< The clients that control this company (Name1, name2, ..)
|
||||
};
|
||||
|
||||
enum NetworkRelayWindowCloseData {
|
||||
NRWCD_UNHANDLED = 0, ///< Relay request is unhandled.
|
||||
NRWCD_HANDLED = 1, ///< Relay request is handled, either by user or by timeout.
|
||||
};
|
||||
|
||||
#endif /* NETWORK_GUI_H */
|
||||
|
||||
@@ -65,39 +65,39 @@ enum NetworkJoinStatus {
|
||||
NETWORK_JOIN_STATUS_END,
|
||||
};
|
||||
|
||||
extern uint32 _frame_counter_server; // The frame_counter of the server, if in network-mode
|
||||
extern uint32 _frame_counter_max; // To where we may go with our clients
|
||||
extern uint32 _frame_counter;
|
||||
extern uint32_t _frame_counter_server; // The frame_counter of the server, if in network-mode
|
||||
extern uint32_t _frame_counter_max; // To where we may go with our clients
|
||||
extern uint32_t _frame_counter;
|
||||
|
||||
extern uint32 _last_sync_frame; // Used in the server to store the last time a sync packet was sent to clients.
|
||||
extern uint32_t _last_sync_frame; // Used in the server to store the last time a sync packet was sent to clients.
|
||||
|
||||
/* networking settings */
|
||||
extern NetworkAddressList _broadcast_list;
|
||||
|
||||
extern uint32 _sync_seed_1;
|
||||
extern uint32_t _sync_seed_1;
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
extern uint32 _sync_seed_2;
|
||||
extern uint32_t _sync_seed_2;
|
||||
#endif
|
||||
extern uint32 _sync_frame;
|
||||
extern uint32_t _sync_frame;
|
||||
extern bool _network_first_time;
|
||||
/* Vars needed for the join-GUI */
|
||||
extern NetworkJoinStatus _network_join_status;
|
||||
extern uint8 _network_join_waiting;
|
||||
extern uint32 _network_join_bytes;
|
||||
extern uint32 _network_join_bytes_total;
|
||||
extern uint8_t _network_join_waiting;
|
||||
extern uint32_t _network_join_bytes;
|
||||
extern uint32_t _network_join_bytes_total;
|
||||
extern ConnectionType _network_server_connection_type;
|
||||
extern std::string _network_server_invite_code;
|
||||
|
||||
/* Variable available for clients. */
|
||||
extern std::string _network_server_name;
|
||||
|
||||
extern uint8 _network_reconnect;
|
||||
extern uint8_t _network_reconnect;
|
||||
|
||||
extern CompanyMask _network_company_passworded;
|
||||
|
||||
void NetworkQueryServer(const std::string &connection_string);
|
||||
|
||||
void GetBindAddresses(NetworkAddressList *addresses, uint16 port);
|
||||
void GetBindAddresses(NetworkAddressList *addresses, uint16_t port);
|
||||
struct NetworkGameList *NetworkAddServer(const std::string &connection_string, bool manually = true, bool never_expire = false);
|
||||
void NetworkRebuildHostList();
|
||||
void UpdateNetworkGameWindow();
|
||||
@@ -107,17 +107,14 @@ void UpdateNetworkGameWindow();
|
||||
* Everything we need to know about a command to be able to execute it.
|
||||
*/
|
||||
struct CommandPacket {
|
||||
/** Make sure the pointer is nullptr. */
|
||||
CommandPacket() : next(nullptr), company(INVALID_COMPANY), frame(0), my_cmd(false), tile(0) {}
|
||||
CommandPacket *next; ///< the next command packet (if in queue)
|
||||
CommandPacket() : company(INVALID_COMPANY), frame(0), my_cmd(false) {}
|
||||
CompanyID company; ///< company that is executing the command
|
||||
uint32 frame; ///< the frame in which this packet is executed
|
||||
uint32_t frame; ///< the frame in which this packet is executed
|
||||
bool my_cmd; ///< did the command originate from "me"
|
||||
|
||||
Commands cmd; ///< command being executed.
|
||||
StringID err_msg; ///< string ID of error message to use.
|
||||
CommandCallback *callback; ///< any callback function executed upon successful completion of the command.
|
||||
TileIndex tile; ///< location of the command (for e.g. error message or effect display).
|
||||
CommandDataBuffer data; ///< command parameters.
|
||||
};
|
||||
|
||||
@@ -128,14 +125,16 @@ void NetworkSyncCommandQueue(NetworkClientSocket *cs);
|
||||
void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id);
|
||||
|
||||
void ShowNetworkError(StringID error_string);
|
||||
void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, const std::string &name, const std::string &str = "", int64 data = 0, const std::string &data_str = "");
|
||||
void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, const std::string &name, const std::string &str = "", int64_t data = 0, const std::string &data_str = "");
|
||||
uint NetworkCalculateLag(const NetworkClientSocket *cs);
|
||||
StringID GetNetworkErrorMsg(NetworkErrorCode err);
|
||||
bool NetworkMakeClientNameUnique(std::string &new_name);
|
||||
std::string GenerateCompanyPasswordHash(const std::string &password, const std::string &password_server_id, uint32 password_game_seed);
|
||||
std::string GenerateCompanyPasswordHash(const std::string &password, const std::string &password_server_id, uint32_t password_game_seed);
|
||||
|
||||
std::string_view ParseCompanyFromConnectionString(const std::string &connection_string, CompanyID *company_id);
|
||||
NetworkAddress ParseConnectionString(const std::string &connection_string, uint16 default_port);
|
||||
std::string NormalizeConnectionString(const std::string &connection_string, uint16 default_port);
|
||||
NetworkAddress ParseConnectionString(const std::string &connection_string, uint16_t default_port);
|
||||
std::string NormalizeConnectionString(const std::string &connection_string, uint16_t default_port);
|
||||
|
||||
void ClientNetworkEmergencySave();
|
||||
|
||||
#endif /* NETWORK_INTERNAL_H */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
/** @file network_query.cpp Query part of the network protocol. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "core/game_info.h"
|
||||
#include "core/network_game_info.h"
|
||||
#include "network_query.h"
|
||||
#include "network_gamelist.h"
|
||||
#include "../error.h"
|
||||
@@ -24,6 +24,15 @@ NetworkRecvStatus QueryNetworkGameSocketHandler::CloseConnection(NetworkRecvStat
|
||||
assert(status != NETWORK_RECV_STATUS_OKAY);
|
||||
assert(this->sock != INVALID_SOCKET);
|
||||
|
||||
/* Connection is closed, but we never received a packet. Must be offline. */
|
||||
NetworkGameList *item = NetworkGameListAddItem(this->connection_string);
|
||||
if (item->refreshing) {
|
||||
item->status = NGLS_OFFLINE;
|
||||
item->refreshing = false;
|
||||
|
||||
UpdateNetworkGameWindow();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -36,6 +45,7 @@ bool QueryNetworkGameSocketHandler::CheckConnection()
|
||||
|
||||
/* If there was no response in 5 seconds, terminate the query. */
|
||||
if (lag > std::chrono::seconds(5)) {
|
||||
Debug(net, 0, "Timeout while waiting for response from {}", this->connection_string);
|
||||
this->CloseConnection(NETWORK_RECV_STATUS_CONNECTION_LOST);
|
||||
return false;
|
||||
}
|
||||
@@ -71,12 +81,16 @@ void QueryNetworkGameSocketHandler::Send()
|
||||
*/
|
||||
NetworkRecvStatus QueryNetworkGameSocketHandler::SendGameInfo()
|
||||
{
|
||||
this->SendPacket(new Packet(PACKET_CLIENT_GAME_INFO));
|
||||
Debug(net, 9, "Query::SendGameInfo()");
|
||||
|
||||
this->SendPacket(std::make_unique<Packet>(PACKET_CLIENT_GAME_INFO));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus QueryNetworkGameSocketHandler::Receive_SERVER_FULL(Packet *p)
|
||||
NetworkRecvStatus QueryNetworkGameSocketHandler::Receive_SERVER_FULL(Packet &)
|
||||
{
|
||||
Debug(net, 9, "Query::Receive_SERVER_FULL()");
|
||||
|
||||
NetworkGameList *item = NetworkGameListAddItem(this->connection_string);
|
||||
item->status = NGLS_FULL;
|
||||
item->refreshing = false;
|
||||
@@ -86,8 +100,10 @@ NetworkRecvStatus QueryNetworkGameSocketHandler::Receive_SERVER_FULL(Packet *p)
|
||||
return NETWORK_RECV_STATUS_CLOSE_QUERY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus QueryNetworkGameSocketHandler::Receive_SERVER_BANNED(Packet *p)
|
||||
NetworkRecvStatus QueryNetworkGameSocketHandler::Receive_SERVER_BANNED(Packet &)
|
||||
{
|
||||
Debug(net, 9, "Query::Receive_SERVER_BANNED()");
|
||||
|
||||
NetworkGameList *item = NetworkGameListAddItem(this->connection_string);
|
||||
item->status = NGLS_BANNED;
|
||||
item->refreshing = false;
|
||||
@@ -97,14 +113,16 @@ NetworkRecvStatus QueryNetworkGameSocketHandler::Receive_SERVER_BANNED(Packet *p
|
||||
return NETWORK_RECV_STATUS_CLOSE_QUERY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus QueryNetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet *p)
|
||||
NetworkRecvStatus QueryNetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet &p)
|
||||
{
|
||||
Debug(net, 9, "Query::Receive_SERVER_GAME_INFO()");
|
||||
|
||||
NetworkGameList *item = NetworkGameListAddItem(this->connection_string);
|
||||
|
||||
/* Clear any existing GRFConfig chain. */
|
||||
ClearGRFConfigList(&item->info.grfconfig);
|
||||
/* Retrieve the NetworkGameInfo from the packet. */
|
||||
DeserializeNetworkGameInfo(p, &item->info);
|
||||
DeserializeNetworkGameInfo(p, item->info);
|
||||
/* Check for compatability with the client. */
|
||||
CheckGameCompatibility(item->info);
|
||||
/* Ensure we consider the server online. */
|
||||
@@ -116,9 +134,11 @@ NetworkRecvStatus QueryNetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet
|
||||
return NETWORK_RECV_STATUS_CLOSE_QUERY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus QueryNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p)
|
||||
NetworkRecvStatus QueryNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet &p)
|
||||
{
|
||||
NetworkErrorCode error = (NetworkErrorCode)p->Recv_uint8();
|
||||
NetworkErrorCode error = (NetworkErrorCode)p.Recv_uint8();
|
||||
|
||||
Debug(net, 9, "Query::Receive_SERVER_ERROR(): error={}", error);
|
||||
|
||||
NetworkGameList *item = NetworkGameListAddItem(this->connection_string);
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ private:
|
||||
std::string connection_string; ///< Address we are connected to.
|
||||
|
||||
protected:
|
||||
NetworkRecvStatus Receive_SERVER_FULL(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_BANNED(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_ERROR(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_GAME_INFO(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_FULL(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_BANNED(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_ERROR(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_GAME_INFO(Packet &p) override;
|
||||
|
||||
NetworkRecvStatus SendGameInfo();
|
||||
|
||||
|
||||
+351
-240
File diff suppressed because it is too large
Load Diff
@@ -23,22 +23,22 @@ extern NetworkClientSocketPool _networkclientsocket_pool;
|
||||
/** Class for handling the server side of the game connection. */
|
||||
class ServerNetworkGameSocketHandler : public NetworkClientSocketPool::PoolItem<&_networkclientsocket_pool>, public NetworkGameSocketHandler, public TCPListenHandler<ServerNetworkGameSocketHandler, PACKET_SERVER_FULL, PACKET_SERVER_BANNED> {
|
||||
protected:
|
||||
NetworkRecvStatus Receive_CLIENT_JOIN(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_GAME_INFO(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_GETMAP(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_ACK(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_COMMAND(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_CHAT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_SET_PASSWORD(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_SET_NAME(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_QUIT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_ERROR(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_RCON(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_NEWGRFS_CHECKED(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_MOVE(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_JOIN(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_GAME_INFO(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_GETMAP(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_ACK(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_COMMAND(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_CHAT(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_SET_PASSWORD(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_SET_NAME(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_QUIT(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_ERROR(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_RCON(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_NEWGRFS_CHECKED(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_MOVE(Packet &p) override;
|
||||
|
||||
NetworkRecvStatus SendGameInfo();
|
||||
NetworkRecvStatus SendNewGRFCheck();
|
||||
@@ -64,18 +64,18 @@ public:
|
||||
|
||||
byte lag_test; ///< Byte used for lag-testing the client
|
||||
byte last_token; ///< The last random token we did send to verify the client is listening
|
||||
uint32 last_token_frame; ///< The last frame we received the right token
|
||||
uint32_t last_token_frame; ///< The last frame we received the right token
|
||||
ClientStatus status; ///< Status of this client
|
||||
CommandQueue outgoing_queue; ///< The command-queue awaiting delivery
|
||||
CommandQueue outgoing_queue; ///< The command-queue awaiting delivery; conceptually more a bucket to gather commands in, after which the whole bucket is sent to the client.
|
||||
size_t receive_limit; ///< Amount of bytes that we can receive at this moment
|
||||
|
||||
struct PacketWriter *savegame; ///< Writer used to write the savegame.
|
||||
std::shared_ptr<struct PacketWriter> savegame; ///< Writer used to write the savegame.
|
||||
NetworkAddress client_address; ///< IP-address of the client (so they can be banned)
|
||||
|
||||
ServerNetworkGameSocketHandler(SOCKET s);
|
||||
~ServerNetworkGameSocketHandler();
|
||||
|
||||
virtual Packet *ReceivePacket() override;
|
||||
std::unique_ptr<Packet> ReceivePacket() override;
|
||||
NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override;
|
||||
std::string GetClientName() const;
|
||||
|
||||
@@ -87,17 +87,17 @@ public:
|
||||
NetworkRecvStatus SendQuit(ClientID client_id);
|
||||
NetworkRecvStatus SendShutdown();
|
||||
NetworkRecvStatus SendNewGame();
|
||||
NetworkRecvStatus SendRConResult(uint16 colour, const std::string &command);
|
||||
NetworkRecvStatus SendRConResult(uint16_t colour, const std::string &command);
|
||||
NetworkRecvStatus SendMove(ClientID client_id, CompanyID company_id);
|
||||
|
||||
NetworkRecvStatus SendClientInfo(NetworkClientInfo *ci);
|
||||
NetworkRecvStatus SendError(NetworkErrorCode error, const std::string &reason = {});
|
||||
NetworkRecvStatus SendChat(NetworkAction action, ClientID client_id, bool self_send, const std::string &msg, int64 data);
|
||||
NetworkRecvStatus SendChat(NetworkAction action, ClientID client_id, bool self_send, const std::string &msg, int64_t data);
|
||||
NetworkRecvStatus SendExternalChat(const std::string &source, TextColour colour, const std::string &user, const std::string &msg);
|
||||
NetworkRecvStatus SendJoin(ClientID client_id);
|
||||
NetworkRecvStatus SendFrame();
|
||||
NetworkRecvStatus SendSync();
|
||||
NetworkRecvStatus SendCommand(const CommandPacket *cp);
|
||||
NetworkRecvStatus SendCommand(const CommandPacket &cp);
|
||||
NetworkRecvStatus SendCompanyUpdate();
|
||||
NetworkRecvStatus SendConfigUpdate();
|
||||
|
||||
@@ -120,6 +120,7 @@ public:
|
||||
};
|
||||
|
||||
void NetworkServer_Tick(bool send_frame);
|
||||
void ChangeNetworkRestartTime(bool reset);
|
||||
void NetworkServerSetCompanyPassword(CompanyID company_id, const std::string &password, bool already_hashed = true);
|
||||
void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class NetworkStunConnecter : public TCPConnecter {
|
||||
private:
|
||||
ClientNetworkStunSocketHandler *stun_handler;
|
||||
std::string token;
|
||||
uint8 family;
|
||||
uint8_t family;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
* @param stun_handler The handler for this request.
|
||||
* @param connection_string The address of the server.
|
||||
*/
|
||||
NetworkStunConnecter(ClientNetworkStunSocketHandler *stun_handler, const std::string &connection_string, const std::string &token, uint8 family) :
|
||||
NetworkStunConnecter(ClientNetworkStunSocketHandler *stun_handler, const std::string &connection_string, const std::string &token, uint8_t family) :
|
||||
TCPConnecter(connection_string, NETWORK_STUN_SERVER_PORT, NetworkAddress(), family),
|
||||
stun_handler(stun_handler),
|
||||
token(token),
|
||||
@@ -38,6 +38,8 @@ public:
|
||||
|
||||
void OnFailure() override
|
||||
{
|
||||
Debug(net, 9, "Stun::OnFailure(): family={}", this->family);
|
||||
|
||||
this->stun_handler->connecter = nullptr;
|
||||
|
||||
/* Connection to STUN server failed. For example, the client doesn't
|
||||
@@ -48,6 +50,8 @@ public:
|
||||
|
||||
void OnConnect(SOCKET s) override
|
||||
{
|
||||
Debug(net, 9, "Stun::OnConnect(): family={}", this->family);
|
||||
|
||||
this->stun_handler->connecter = nullptr;
|
||||
|
||||
assert(this->stun_handler->sock == INVALID_SOCKET);
|
||||
@@ -66,12 +70,14 @@ public:
|
||||
* @param token The token as received from the Game Coordinator.
|
||||
* @param family What IP family to use.
|
||||
*/
|
||||
void ClientNetworkStunSocketHandler::Connect(const std::string &token, uint8 family)
|
||||
void ClientNetworkStunSocketHandler::Connect(const std::string &token, uint8_t family)
|
||||
{
|
||||
this->token = token;
|
||||
this->family = family;
|
||||
|
||||
this->connecter = new NetworkStunConnecter(this, NetworkStunConnectionString(), token, family);
|
||||
Debug(net, 9, "Stun::Connect(): family={}", this->family);
|
||||
|
||||
this->connecter = TCPConnecter::Create<NetworkStunConnecter>(this, NetworkStunConnectionString(), token, family);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,18 +86,18 @@ void ClientNetworkStunSocketHandler::Connect(const std::string &token, uint8 fam
|
||||
* @param family What IP family this STUN request is for.
|
||||
* @return The handler for this STUN request.
|
||||
*/
|
||||
std::unique_ptr<ClientNetworkStunSocketHandler> ClientNetworkStunSocketHandler::Stun(const std::string &token, uint8 family)
|
||||
std::unique_ptr<ClientNetworkStunSocketHandler> ClientNetworkStunSocketHandler::Stun(const std::string &token, uint8_t family)
|
||||
{
|
||||
auto stun_handler = std::make_unique<ClientNetworkStunSocketHandler>();
|
||||
|
||||
stun_handler->Connect(token, family);
|
||||
|
||||
Packet *p = new Packet(PACKET_STUN_SERCLI_STUN);
|
||||
auto p = std::make_unique<Packet>(PACKET_STUN_SERCLI_STUN);
|
||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||
p->Send_string(token);
|
||||
p->Send_uint8(family);
|
||||
|
||||
stun_handler->SendPacket(p);
|
||||
stun_handler->SendPacket(std::move(p));
|
||||
|
||||
return stun_handler;
|
||||
}
|
||||
|
||||
@@ -16,20 +16,20 @@
|
||||
class ClientNetworkStunSocketHandler : public NetworkStunSocketHandler {
|
||||
private:
|
||||
std::string token; ///< Token of this STUN handler.
|
||||
uint8 family = AF_UNSPEC; ///< Family of this STUN handler.
|
||||
uint8_t family = AF_UNSPEC; ///< Family of this STUN handler.
|
||||
bool sent_result = false; ///< Did we sent the result of the STUN connection?
|
||||
|
||||
public:
|
||||
TCPConnecter *connecter = nullptr; ///< Connecter instance.
|
||||
std::shared_ptr<TCPConnecter> connecter{}; ///< Connecter instance.
|
||||
NetworkAddress local_addr; ///< Local addresses of the socket.
|
||||
|
||||
NetworkRecvStatus CloseConnection(bool error = true) override;
|
||||
~ClientNetworkStunSocketHandler() override;
|
||||
void SendReceive();
|
||||
|
||||
void Connect(const std::string &token, uint8 family);
|
||||
void Connect(const std::string &token, uint8_t family);
|
||||
|
||||
static std::unique_ptr<ClientNetworkStunSocketHandler> Stun(const std::string &token, uint8 family);
|
||||
static std::unique_ptr<ClientNetworkStunSocketHandler> Stun(const std::string &token, uint8_t family);
|
||||
};
|
||||
|
||||
#endif /* NETWORK_STUN_H */
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 network_survey.cpp Opt-in survey part of the network protocol. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "network_survey.h"
|
||||
#include "settings_table.h"
|
||||
#include "network.h"
|
||||
#include "network_func.h"
|
||||
#include "../debug.h"
|
||||
#include "../survey.h"
|
||||
#include "../3rdparty/fmt/chrono.h"
|
||||
#include "../3rdparty/fmt/std.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
extern std::string _savegame_id;
|
||||
|
||||
NetworkSurveyHandler _survey = {};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(NetworkSurveyHandler::Reason, {
|
||||
{NetworkSurveyHandler::Reason::PREVIEW, "preview"},
|
||||
{NetworkSurveyHandler::Reason::LEAVE, "leave"},
|
||||
{NetworkSurveyHandler::Reason::EXIT, "exit"},
|
||||
{NetworkSurveyHandler::Reason::CRASH, "crash"},
|
||||
})
|
||||
|
||||
/**
|
||||
* Create the payload for the survey.
|
||||
*
|
||||
* @param reason The reason for sending the survey.
|
||||
* @param for_preview Whether the payload is meant for preview. This indents the result, and filters out the id/key.
|
||||
* @return std::string The JSON payload as string for the survey.
|
||||
*/
|
||||
std::string NetworkSurveyHandler::CreatePayload(Reason reason, bool for_preview)
|
||||
{
|
||||
nlohmann::json survey;
|
||||
|
||||
survey["schema"] = NETWORK_SURVEY_VERSION;
|
||||
survey["reason"] = reason;
|
||||
survey["id"] = _savegame_id;
|
||||
survey["date"] = fmt::format("{:%Y-%m-%d %H:%M:%S} (UTC)", fmt::gmtime(time(nullptr)));
|
||||
|
||||
#ifdef SURVEY_KEY
|
||||
/* We censor the key to avoid people trying to be "clever" and use it to send their own surveys. */
|
||||
survey["key"] = for_preview ? "(redacted)" : SURVEY_KEY;
|
||||
#else
|
||||
survey["key"] = "";
|
||||
#endif
|
||||
|
||||
{
|
||||
auto &info = survey["info"];
|
||||
SurveyOS(info["os"]);
|
||||
SurveyOpenTTD(info["openttd"]);
|
||||
SurveyConfiguration(info["configuration"]);
|
||||
SurveyFont(info["font"]);
|
||||
SurveyCompiler(info["compiler"]);
|
||||
SurveyLibraries(info["libraries"]);
|
||||
SurveyPlugins(info["plugins"]);
|
||||
}
|
||||
|
||||
{
|
||||
auto &game = survey["game"];
|
||||
SurveyTimers(game["timers"]);
|
||||
SurveyCompanies(game["companies"]);
|
||||
SurveySettings(game["settings"], false);
|
||||
SurveyGrfs(game["grfs"]);
|
||||
SurveyGameScript(game["game_script"]);
|
||||
}
|
||||
|
||||
/* For preview, we indent with 4 whitespaces to make things more readable. */
|
||||
int indent = for_preview ? 4 : -1;
|
||||
return survey.dump(indent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit the survey.
|
||||
*
|
||||
* @param reason The reason for sending the survey.
|
||||
* @param blocking Whether to block until the survey is sent.
|
||||
*/
|
||||
void NetworkSurveyHandler::Transmit(Reason reason, bool blocking)
|
||||
{
|
||||
if constexpr (!NetworkSurveyHandler::IsSurveyPossible()) {
|
||||
Debug(net, 4, "Survey: not possible to send survey; most likely due to missing JSON library at compile-time");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_settings_client.network.participate_survey != PS_YES) {
|
||||
Debug(net, 5, "Survey: user is not participating in survey; skipping survey");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug(net, 1, "Survey: sending survey results");
|
||||
NetworkHTTPSocketHandler::Connect(NetworkSurveyUriString(), this, this->CreatePayload(reason));
|
||||
|
||||
if (blocking) {
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
|
||||
/* Block no longer than 2 seconds. If we failed to send the survey in that time, so be it. */
|
||||
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now() + std::chrono::seconds(2);
|
||||
|
||||
while (!this->transmitted && std::chrono::steady_clock::now() < end) {
|
||||
NetworkBackgroundLoop();
|
||||
this->transmitted_cv.wait_for(lock, std::chrono::milliseconds(30));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkSurveyHandler::OnFailure()
|
||||
{
|
||||
Debug(net, 1, "Survey: failed to send survey results");
|
||||
this->transmitted = true;
|
||||
this->transmitted_cv.notify_all();
|
||||
}
|
||||
|
||||
void NetworkSurveyHandler::OnReceiveData(std::unique_ptr<char[]> data, size_t)
|
||||
{
|
||||
if (data == nullptr) {
|
||||
Debug(net, 1, "Survey: survey results sent");
|
||||
this->transmitted = true;
|
||||
this->transmitted_cv.notify_all();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 network_survey.h Part of the network protocol handling opt-in survey. */
|
||||
|
||||
#ifndef NETWORK_SURVEY_H
|
||||
#define NETWORK_SURVEY_H
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include "core/http.h"
|
||||
|
||||
/**
|
||||
* Socket handler for the survey connection
|
||||
*/
|
||||
class NetworkSurveyHandler : public HTTPCallback {
|
||||
protected:
|
||||
void OnFailure() override;
|
||||
void OnReceiveData(std::unique_ptr<char[]> data, size_t length) override;
|
||||
bool IsCancelled() const override { return false; }
|
||||
|
||||
public:
|
||||
enum class Reason {
|
||||
PREVIEW, ///< User is previewing the survey result.
|
||||
LEAVE, ///< User is leaving the game (but not exiting the application).
|
||||
EXIT, ///< User is exiting the application.
|
||||
CRASH, ///< Game crashed.
|
||||
};
|
||||
|
||||
void Transmit(Reason reason, bool blocking = false);
|
||||
std::string CreatePayload(Reason reason, bool for_preview = false);
|
||||
|
||||
constexpr static bool IsSurveyPossible()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex; ///< Mutex for the condition variable.
|
||||
std::atomic<bool> transmitted; ///< Whether the survey has been transmitted.
|
||||
std::condition_variable transmitted_cv; ///< Condition variable to inform changes to transmitted.
|
||||
};
|
||||
|
||||
extern NetworkSurveyHandler _survey;
|
||||
|
||||
#endif /* NETWORK_SURVEY_H */
|
||||
@@ -32,6 +32,8 @@ public:
|
||||
|
||||
void OnFailure() override
|
||||
{
|
||||
Debug(net, 9, "Turn::OnFailure()");
|
||||
|
||||
this->handler->connecter = nullptr;
|
||||
|
||||
this->handler->ConnectFailure();
|
||||
@@ -39,22 +41,28 @@ public:
|
||||
|
||||
void OnConnect(SOCKET s) override
|
||||
{
|
||||
Debug(net, 9, "Turn::OnConnect()");
|
||||
|
||||
this->handler->connecter = nullptr;
|
||||
|
||||
this->handler->sock = s;
|
||||
}
|
||||
};
|
||||
|
||||
bool ClientNetworkTurnSocketHandler::Receive_TURN_ERROR(Packet *p)
|
||||
bool ClientNetworkTurnSocketHandler::Receive_TURN_ERROR(Packet &)
|
||||
{
|
||||
Debug(net, 9, "Receive_TURN_ERROR()");
|
||||
|
||||
this->ConnectFailure();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ClientNetworkTurnSocketHandler::Receive_TURN_CONNECTED(Packet *p)
|
||||
bool ClientNetworkTurnSocketHandler::Receive_TURN_CONNECTED(Packet &p)
|
||||
{
|
||||
std::string hostname = p->Recv_string(NETWORK_HOSTNAME_LENGTH);
|
||||
Debug(net, 9, "Receive_TURN_CONNECTED()");
|
||||
|
||||
std::string hostname = p.Recv_string(NETWORK_HOSTNAME_LENGTH);
|
||||
|
||||
/* Act like we no longer have a socket, as we are handing it over to the
|
||||
* game handler. */
|
||||
@@ -72,8 +80,10 @@ bool ClientNetworkTurnSocketHandler::Receive_TURN_CONNECTED(Packet *p)
|
||||
*/
|
||||
void ClientNetworkTurnSocketHandler::Connect()
|
||||
{
|
||||
Debug(net, 9, "Turn::Connect()");
|
||||
|
||||
this->connect_started = true;
|
||||
this->connecter = new NetworkTurnConnecter(this, this->connection_string);
|
||||
this->connecter = TCPConnecter::Create<NetworkTurnConnecter>(this, this->connection_string);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,15 +96,15 @@ void ClientNetworkTurnSocketHandler::Connect()
|
||||
* @param connection_string Connection string of the TURN server.
|
||||
* @return The handler for this TURN connection.
|
||||
*/
|
||||
/* static */ std::unique_ptr<ClientNetworkTurnSocketHandler> ClientNetworkTurnSocketHandler::Turn(const std::string &token, uint8 tracking_number, const std::string &ticket, const std::string &connection_string)
|
||||
/* static */ std::unique_ptr<ClientNetworkTurnSocketHandler> ClientNetworkTurnSocketHandler::Turn(const std::string &token, uint8_t tracking_number, const std::string &ticket, const std::string &connection_string)
|
||||
{
|
||||
auto turn_handler = std::make_unique<ClientNetworkTurnSocketHandler>(token, tracking_number, connection_string);
|
||||
|
||||
Packet *p = new Packet(PACKET_TURN_SERCLI_CONNECT);
|
||||
auto p = std::make_unique<Packet>(PACKET_TURN_SERCLI_CONNECT);
|
||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||
p->Send_string(ticket);
|
||||
|
||||
turn_handler->SendPacket(p);
|
||||
turn_handler->SendPacket(std::move(p));
|
||||
|
||||
return turn_handler;
|
||||
}
|
||||
|
||||
@@ -16,18 +16,18 @@
|
||||
class ClientNetworkTurnSocketHandler : public NetworkTurnSocketHandler {
|
||||
private:
|
||||
std::string token; ///< Token of this connection.
|
||||
uint8 tracking_number; ///< Tracking number of this connection.
|
||||
uint8_t tracking_number; ///< Tracking number of this connection.
|
||||
std::string connection_string; ///< The connection string of the TURN server we are connecting to.
|
||||
|
||||
protected:
|
||||
bool Receive_TURN_ERROR(Packet *p) override;
|
||||
bool Receive_TURN_CONNECTED(Packet *p) override;
|
||||
bool Receive_TURN_ERROR(Packet &p) override;
|
||||
bool Receive_TURN_CONNECTED(Packet &p) override;
|
||||
|
||||
public:
|
||||
TCPConnecter *connecter = nullptr; ///< Connecter instance.
|
||||
std::shared_ptr<TCPConnecter> connecter{}; ///< Connecter instance.
|
||||
bool connect_started = false; ///< Whether we started the connection.
|
||||
|
||||
ClientNetworkTurnSocketHandler(const std::string &token, uint8 tracking_number, const std::string &connection_string) : token(token), tracking_number(tracking_number), connection_string(connection_string) {}
|
||||
ClientNetworkTurnSocketHandler(const std::string &token, uint8_t tracking_number, const std::string &connection_string) : token(token), tracking_number(tracking_number), connection_string(connection_string) {}
|
||||
|
||||
NetworkRecvStatus CloseConnection(bool error = true) override;
|
||||
~ClientNetworkTurnSocketHandler() override;
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
void Connect();
|
||||
void ConnectFailure();
|
||||
|
||||
static std::unique_ptr<ClientNetworkTurnSocketHandler> Turn(const std::string &token, uint8 tracking_number, const std::string &ticket, const std::string &connection_string);
|
||||
static std::unique_ptr<ClientNetworkTurnSocketHandler> Turn(const std::string &token, uint8_t tracking_number, const std::string &ticket, const std::string &connection_string);
|
||||
};
|
||||
|
||||
#endif /* NETWORK_TURN_H */
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#ifndef NETWORK_TYPE_H
|
||||
#define NETWORK_TYPE_H
|
||||
|
||||
#include "../core/enum_type.hpp"
|
||||
|
||||
/** How many clients can we have */
|
||||
static const uint MAX_CLIENTS = 255;
|
||||
|
||||
@@ -37,24 +39,24 @@ enum NetworkVehicleType {
|
||||
* Game type the server can be using.
|
||||
* Used on the network protocol to communicate with Game Coordinator.
|
||||
*/
|
||||
enum ServerGameType : uint8 {
|
||||
enum ServerGameType : uint8_t {
|
||||
SERVER_GAME_TYPE_LOCAL = 0,
|
||||
SERVER_GAME_TYPE_PUBLIC,
|
||||
SERVER_GAME_TYPE_INVITE_ONLY,
|
||||
};
|
||||
|
||||
/** 'Unique' identifier to be given to clients */
|
||||
enum ClientID : uint32 {
|
||||
enum ClientID : uint32_t {
|
||||
INVALID_CLIENT_ID = 0, ///< Client is not part of anything
|
||||
CLIENT_ID_SERVER = 1, ///< Servers always have this ID
|
||||
CLIENT_ID_FIRST = 2, ///< The first client ID
|
||||
};
|
||||
|
||||
/** Indices into the client tables */
|
||||
typedef uint8 ClientIndex;
|
||||
typedef uint8_t ClientIndex;
|
||||
|
||||
/** Indices into the admin tables. */
|
||||
typedef uint8 AdminIndex;
|
||||
typedef uint8_t AdminIndex;
|
||||
|
||||
/** Maximum number of allowed admins. */
|
||||
static const AdminIndex MAX_ADMINS = 16;
|
||||
@@ -63,15 +65,15 @@ static const AdminIndex INVALID_ADMIN_ID = UINT8_MAX;
|
||||
|
||||
/** Simple calculated statistics of a company */
|
||||
struct NetworkCompanyStats {
|
||||
uint16 num_vehicle[NETWORK_VEH_END]; ///< How many vehicles are there of this type?
|
||||
uint16 num_station[NETWORK_VEH_END]; ///< How many stations are there of this type?
|
||||
uint16_t num_vehicle[NETWORK_VEH_END]; ///< How many vehicles are there of this type?
|
||||
uint16_t num_station[NETWORK_VEH_END]; ///< How many stations are there of this type?
|
||||
bool ai; ///< Is this company an AI
|
||||
};
|
||||
|
||||
/** Some state information of a company, especially for servers */
|
||||
struct NetworkCompanyState {
|
||||
std::string password; ///< The password for the company
|
||||
uint16 months_empty; ///< How many months the company is empty
|
||||
uint16_t months_empty; ///< How many months the company is empty
|
||||
};
|
||||
|
||||
struct NetworkClientInfo;
|
||||
@@ -86,11 +88,12 @@ enum NetworkPasswordType {
|
||||
* Destination of our chat messages.
|
||||
* @warning The values of the enum items are part of the admin network API. Only append at the end.
|
||||
*/
|
||||
enum DestType {
|
||||
enum DestType : byte {
|
||||
DESTTYPE_BROADCAST, ///< Send message/notice to all clients (All)
|
||||
DESTTYPE_TEAM, ///< Send message/notice to everyone playing the same company (Team)
|
||||
DESTTYPE_CLIENT, ///< Send message/notice to only a certain client (Private)
|
||||
};
|
||||
DECLARE_ENUM_AS_ADDABLE(DestType)
|
||||
|
||||
/**
|
||||
* Actions that can be used for NetworkTextMessage.
|
||||
|
||||
+14
-14
@@ -13,10 +13,10 @@
|
||||
*/
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../date_func.h"
|
||||
#include "../timer/timer_game_calendar.h"
|
||||
#include "../map_func.h"
|
||||
#include "../debug.h"
|
||||
#include "core/game_info.h"
|
||||
#include "core/network_game_info.h"
|
||||
#include "network_gamelist.h"
|
||||
#include "network_internal.h"
|
||||
#include "network_udp.h"
|
||||
@@ -33,7 +33,7 @@
|
||||
#include "../safeguards.h"
|
||||
|
||||
static bool _network_udp_server; ///< Is the UDP server started?
|
||||
static uint16 _network_udp_broadcast; ///< Timeout for the UDP broadcasts.
|
||||
static uint16_t _network_udp_broadcast; ///< Timeout for the UDP broadcasts.
|
||||
|
||||
/** Some information about a socket, which exists before the actual socket has been created to provide locking and the likes. */
|
||||
struct UDPSocket {
|
||||
@@ -63,22 +63,22 @@ static UDPSocket _udp_server("Server"); ///< udp server socket
|
||||
/** Helper class for handling all server side communication. */
|
||||
class ServerNetworkUDPSocketHandler : public NetworkUDPSocketHandler {
|
||||
protected:
|
||||
void Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) override;
|
||||
void Receive_CLIENT_FIND_SERVER(Packet &p, NetworkAddress &client_addr) override;
|
||||
public:
|
||||
/**
|
||||
* Create the socket.
|
||||
* @param addresses The addresses to bind on.
|
||||
*/
|
||||
ServerNetworkUDPSocketHandler(NetworkAddressList *addresses) : NetworkUDPSocketHandler(addresses) {}
|
||||
virtual ~ServerNetworkUDPSocketHandler() {}
|
||||
virtual ~ServerNetworkUDPSocketHandler() = default;
|
||||
};
|
||||
|
||||
void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr)
|
||||
void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet &, NetworkAddress &client_addr)
|
||||
{
|
||||
Packet packet(PACKET_UDP_SERVER_RESPONSE);
|
||||
this->SendPacket(&packet, client_addr);
|
||||
this->SendPacket(packet, client_addr);
|
||||
|
||||
Debug(net, 7, "Queried from {}", client_addr->GetHostname());
|
||||
Debug(net, 7, "Queried from {}", client_addr.GetHostname());
|
||||
}
|
||||
|
||||
///*** Communication with servers (we are client) ***/
|
||||
@@ -86,16 +86,16 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, Networ
|
||||
/** Helper class for handling all client side communication. */
|
||||
class ClientNetworkUDPSocketHandler : public NetworkUDPSocketHandler {
|
||||
protected:
|
||||
void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) override;
|
||||
void Receive_SERVER_RESPONSE(Packet &p, NetworkAddress &client_addr) override;
|
||||
public:
|
||||
virtual ~ClientNetworkUDPSocketHandler() {}
|
||||
virtual ~ClientNetworkUDPSocketHandler() = default;
|
||||
};
|
||||
|
||||
void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr)
|
||||
void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet &, NetworkAddress &client_addr)
|
||||
{
|
||||
Debug(net, 3, "Server response from {}", client_addr->GetAddressAsString());
|
||||
Debug(net, 3, "Server response from {}", client_addr.GetAddressAsString());
|
||||
|
||||
NetworkAddServer(client_addr->GetAddressAsString(false), false, true);
|
||||
NetworkAddServer(client_addr.GetAddressAsString(false), false, true);
|
||||
}
|
||||
|
||||
/** Broadcast to all ips */
|
||||
@@ -105,7 +105,7 @@ static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket)
|
||||
Debug(net, 5, "Broadcasting to {}", addr.GetHostname());
|
||||
|
||||
Packet p(PACKET_UDP_CLIENT_FIND_SERVER);
|
||||
socket->SendPacket(&p, &addr, true, true);
|
||||
socket->SendPacket(p, addr, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user