Merge branch 'master' into jgrpp-beta
# Conflicts: # .github/workflows/ci-build.yml # src/lang/german.txt # src/lang/romanian.txt # src/lang/slovak.txt # src/lang/turkish.txt # src/network/core/address.cpp # src/network/core/tcp.h # src/network/core/udp.cpp # src/network/network.cpp # src/network/network_client.cpp # src/network/network_server.cpp # src/network/network_server.h # src/network/network_udp.cpp # src/openttd.cpp # src/saveload/newgrf_sl.cpp # src/tree_cmd.cpp # src/video/video_driver.hpp # src/window.cpp # src/window_gui.h
This commit is contained in:
@@ -14,8 +14,6 @@
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
static const int DEFAULT_CONNECT_TIMEOUT_SECONDS = 3; ///< Allow connect() three seconds to connect.
|
||||
|
||||
/**
|
||||
* Get the hostname; in case it wasn't given the
|
||||
* IPv4 dotted representation is given.
|
||||
@@ -316,82 +314,6 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
|
||||
return sock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to resolve a connected socket.
|
||||
* @param runp information about the socket to try not
|
||||
* @return the opened socket or INVALID_SOCKET
|
||||
*/
|
||||
static SOCKET ConnectLoopProc(addrinfo *runp)
|
||||
{
|
||||
const char *type = NetworkAddress::SocketTypeAsString(runp->ai_socktype);
|
||||
const char *family = NetworkAddress::AddressFamilyAsString(runp->ai_family);
|
||||
std::string address = NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString();
|
||||
|
||||
SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
DEBUG(net, 1, "[%s] could not create %s socket: %s", type, family, NetworkError::GetLast().AsString());
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (!SetNoDelay(sock)) DEBUG(net, 1, "[%s] setting TCP_NODELAY failed", type);
|
||||
|
||||
if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed", type);
|
||||
|
||||
int err = connect(sock, runp->ai_addr, (int)runp->ai_addrlen);
|
||||
if (err != 0 && !NetworkError::GetLast().IsConnectInProgress()) {
|
||||
DEBUG(net, 1, "[%s] could not connect to %s over %s: %s", type, address.c_str(), family, NetworkError::GetLast().AsString());
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
fd_set write_fd;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&write_fd);
|
||||
FD_SET(sock, &write_fd);
|
||||
|
||||
/* Wait for connect() to either connect, timeout or fail. */
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = DEFAULT_CONNECT_TIMEOUT_SECONDS;
|
||||
int n = select(FD_SETSIZE, NULL, &write_fd, NULL, &tv);
|
||||
if (n < 0) {
|
||||
DEBUG(net, 1, "[%s] could not connect to %s: %s", type, address.c_str(), NetworkError::GetLast().AsString());
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/* If no fd is selected, the timeout has been reached. */
|
||||
if (n == 0) {
|
||||
DEBUG(net, 1, "[%s] timed out while connecting to %s", type, address.c_str());
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/* Retrieve last error, if any, on the socket. */
|
||||
NetworkError socket_error = GetSocketError(sock);
|
||||
if (socket_error.HasError()) {
|
||||
DEBUG(net, 1, "[%s] could not connect to %s: %s", type, address.c_str(), socket_error.AsString());
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/* Connection succeeded. */
|
||||
DEBUG(net, 1, "[%s] connected to %s", type, address.c_str());
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the given address.
|
||||
* @return the connected socket or INVALID_SOCKET.
|
||||
*/
|
||||
SOCKET NetworkAddress::Connect()
|
||||
{
|
||||
DEBUG(net, 1, "Connecting to %s", NetworkAddressDumper().GetAddressAsString(this));
|
||||
|
||||
return this->Resolve(AF_UNSPEC, SOCK_STREAM, AI_ADDRCONFIG, nullptr, ConnectLoopProc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to resolve a listening.
|
||||
* @param runp information about the socket to try not
|
||||
@@ -399,49 +321,52 @@ SOCKET NetworkAddress::Connect()
|
||||
*/
|
||||
static SOCKET ListenLoopProc(addrinfo *runp)
|
||||
{
|
||||
const char *type = NetworkAddress::SocketTypeAsString(runp->ai_socktype);
|
||||
const char *family = NetworkAddress::AddressFamilyAsString(runp->ai_family);
|
||||
std::string address = NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString();
|
||||
|
||||
SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
DEBUG(net, 0, "[%s] could not create %s socket on port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString());
|
||||
const char *type = NetworkAddress::SocketTypeAsString(runp->ai_socktype);
|
||||
const char *family = NetworkAddress::AddressFamilyAsString(runp->ai_family);
|
||||
DEBUG(net, 0, "Could not create %s %s socket: %s", type, family, NetworkError::GetLast().AsString());
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (runp->ai_socktype == SOCK_STREAM && !SetNoDelay(sock)) {
|
||||
DEBUG(net, 3, "[%s] setting TCP_NODELAY failed for port %s", type, address.c_str());
|
||||
DEBUG(net, 1, "Setting no-delay mode failed: %s", NetworkError::GetLast().AsString());
|
||||
}
|
||||
|
||||
int on = 1;
|
||||
/* The (const char*) cast is needed for windows!! */
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1) {
|
||||
DEBUG(net, 3, "[%s] could not set reusable %s sockets for port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString());
|
||||
DEBUG(net, 0, "Setting reuse-address mode failed: %s", NetworkError::GetLast().AsString());
|
||||
}
|
||||
|
||||
#ifndef __OS2__
|
||||
if (runp->ai_family == AF_INET6 &&
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) == -1) {
|
||||
DEBUG(net, 3, "[%s] could not disable IPv4 over IPv6 on port %s: %s", type, address.c_str(), NetworkError::GetLast().AsString());
|
||||
DEBUG(net, 3, "Could not disable IPv4 over IPv6: %s", NetworkError::GetLast().AsString());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bind(sock, runp->ai_addr, (int)runp->ai_addrlen) != 0) {
|
||||
DEBUG(net, 1, "[%s] could not bind on %s port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString());
|
||||
DEBUG(net, 0, "Could not bind socket on %s: %s", address.c_str(), NetworkError::GetLast().AsString());
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (runp->ai_socktype != SOCK_DGRAM && listen(sock, 1) != 0) {
|
||||
DEBUG(net, 1, "[%s] could not listen at %s port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString());
|
||||
DEBUG(net, 0, "Could not listen on socket: %s", NetworkError::GetLast().AsString());
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/* Connection succeeded */
|
||||
if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed for %s port %s", type, family, address.c_str());
|
||||
|
||||
DEBUG(net, 1, "[%s] listening on %s port %s", type, family, address.c_str());
|
||||
if (!SetNonBlocking(sock)) {
|
||||
DEBUG(net, 0, "Setting non-blocking mode failed: %s", NetworkError::GetLast().AsString());
|
||||
}
|
||||
|
||||
DEBUG(net, 3, "Listening on %s", address.c_str());
|
||||
return sock;
|
||||
}
|
||||
|
||||
@@ -496,3 +421,16 @@ void NetworkAddress::Listen(int socktype, SocketList *sockets)
|
||||
default: return "unsupported";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the peer name of a socket in string format.
|
||||
* @param sock The socket to get the peer name of.
|
||||
* @return The string representation of the peer name.
|
||||
*/
|
||||
/* static */ const std::string NetworkAddress::GetPeerName(SOCKET sock)
|
||||
{
|
||||
sockaddr_storage addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
getpeername(sock, (sockaddr *)&addr, &addr_len);
|
||||
return NetworkAddress(addr, addr_len).GetAddressAsString();
|
||||
}
|
||||
|
||||
@@ -171,11 +171,11 @@ public:
|
||||
return this->CompareTo(address) < 0;
|
||||
}
|
||||
|
||||
SOCKET Connect();
|
||||
void Listen(int socktype, SocketList *sockets);
|
||||
|
||||
static const char *SocketTypeAsString(int socktype);
|
||||
static const char *AddressFamilyAsString(int family);
|
||||
static const std::string GetPeerName(SOCKET sock);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,9 +27,9 @@ bool NetworkCoreInitialize()
|
||||
#ifdef _WIN32
|
||||
{
|
||||
WSADATA wsa;
|
||||
DEBUG(net, 3, "[core] loading windows socket library");
|
||||
DEBUG(net, 5, "Loading windows socket library");
|
||||
if (WSAStartup(MAKEWORD(2, 0), &wsa) != 0) {
|
||||
DEBUG(net, 0, "[core] WSAStartup failed, network unavailable");
|
||||
DEBUG(net, 0, "WSAStartup failed, network unavailable");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,16 +20,17 @@ void NetworkCoreShutdown();
|
||||
|
||||
/** Status of a network client; reasons why a client has quit */
|
||||
enum NetworkRecvStatus {
|
||||
NETWORK_RECV_STATUS_OKAY, ///< Everything is okay
|
||||
NETWORK_RECV_STATUS_DESYNC, ///< A desync did occur
|
||||
NETWORK_RECV_STATUS_NEWGRF_MISMATCH, ///< We did not have the required NewGRFs
|
||||
NETWORK_RECV_STATUS_SAVEGAME, ///< Something went wrong (down)loading the savegame
|
||||
NETWORK_RECV_STATUS_CONN_LOST, ///< The connection is 'just' lost
|
||||
NETWORK_RECV_STATUS_MALFORMED_PACKET, ///< We apparently send a malformed packet
|
||||
NETWORK_RECV_STATUS_SERVER_ERROR, ///< The server told us we made an error
|
||||
NETWORK_RECV_STATUS_SERVER_FULL, ///< The server is full
|
||||
NETWORK_RECV_STATUS_SERVER_BANNED, ///< The server has banned us
|
||||
NETWORK_RECV_STATUS_CLOSE_QUERY, ///< Done querying the server
|
||||
NETWORK_RECV_STATUS_OKAY, ///< Everything is okay.
|
||||
NETWORK_RECV_STATUS_DESYNC, ///< A desync did occur.
|
||||
NETWORK_RECV_STATUS_NEWGRF_MISMATCH, ///< We did not have the required NewGRFs.
|
||||
NETWORK_RECV_STATUS_SAVEGAME, ///< Something went wrong (down)loading the savegame.
|
||||
NETWORK_RECV_STATUS_CLIENT_QUIT, ///< The connection is lost gracefully. Other clients are already informed of this leaving client.
|
||||
NETWORK_RECV_STATUS_MALFORMED_PACKET, ///< We apparently send a malformed packet.
|
||||
NETWORK_RECV_STATUS_SERVER_ERROR, ///< The server told us we made an error.
|
||||
NETWORK_RECV_STATUS_SERVER_FULL, ///< The server is full.
|
||||
NETWORK_RECV_STATUS_SERVER_BANNED, ///< The server has banned us.
|
||||
NETWORK_RECV_STATUS_CLOSE_QUERY, ///< Done querying the server.
|
||||
NETWORK_RECV_STATUS_CONNECTION_LOST, ///< The connection is lost unexpectedly.
|
||||
};
|
||||
|
||||
/** Forward declaration due to circular dependencies */
|
||||
@@ -45,10 +46,7 @@ public:
|
||||
NetworkSocketHandler() { this->has_quit = false; }
|
||||
|
||||
/** Close the socket when destructing the socket handler */
|
||||
virtual ~NetworkSocketHandler() { this->Close(); }
|
||||
|
||||
/** Really close the socket */
|
||||
virtual void Close() {}
|
||||
virtual ~NetworkSocketHandler() {}
|
||||
|
||||
/**
|
||||
* Close the current connection; for TCP this will be mostly equivalent
|
||||
|
||||
@@ -52,7 +52,7 @@ const char *GetNetworkRevisionString()
|
||||
|
||||
/* Tag names are not mangled further. */
|
||||
if (_openttd_revision_tagged) {
|
||||
DEBUG(net, 1, "Network revision name is '%s'", network_revision);
|
||||
DEBUG(net, 3, "Network revision name: %s", network_revision);
|
||||
return network_revision;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ const char *GetNetworkRevisionString()
|
||||
/* Replace the git hash in revision string. */
|
||||
strecpy(network_revision + hashofs, githash_suffix, network_revision + NETWORK_REVISION_LENGTH);
|
||||
assert(strlen(network_revision) < NETWORK_REVISION_LENGTH); // strlen does not include terminator, constant does, hence strictly less than
|
||||
DEBUG(net, 1, "Network revision name is '%s'", network_revision);
|
||||
DEBUG(net, 3, "Network revision name: %s", network_revision);
|
||||
}
|
||||
|
||||
return network_revision;
|
||||
|
||||
@@ -39,14 +39,14 @@ static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // BE
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
if (sock < 0) {
|
||||
DEBUG(net, 0, "[core] error creating socket");
|
||||
DEBUG(net, 0, "Could not create socket: %s", NetworkError::GetLast().AsString());
|
||||
return;
|
||||
}
|
||||
|
||||
char *output_pointer = nullptr;
|
||||
int output_length = _netstat(sock, &output_pointer, 1);
|
||||
if (output_length < 0) {
|
||||
DEBUG(net, 0, "[core] error running _netstat");
|
||||
DEBUG(net, 0, "Error running _netstat()");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -205,6 +205,6 @@ void NetworkFindBroadcastIPs(NetworkAddressList *broadcast)
|
||||
int i = 0;
|
||||
for (NetworkAddress &addr : *broadcast) {
|
||||
addr.SetPort(NETWORK_DEFAULT_PORT);
|
||||
DEBUG(net, 3, "%d) %s", i++, addr.GetHostname());
|
||||
DEBUG(net, 3, " %d) %s", i++, addr.GetHostname());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ NetworkTCPSocketHandler::NetworkTCPSocketHandler(SOCKET s) :
|
||||
|
||||
NetworkTCPSocketHandler::~NetworkTCPSocketHandler()
|
||||
{
|
||||
this->CloseConnection();
|
||||
/* Virtual functions get called statically in destructors, so make it explicit to remove any confusion. */
|
||||
this->NetworkTCPSocketHandler::CloseConnection();
|
||||
|
||||
if (this->sock != INVALID_SOCKET) closesocket(this->sock);
|
||||
this->sock = INVALID_SOCKET;
|
||||
@@ -118,7 +119,7 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down)
|
||||
if (!err.WouldBlock()) {
|
||||
/* Something went wrong.. close client! */
|
||||
if (!closing_down) {
|
||||
DEBUG(net, 0, "send failed with error %s", err.AsString());
|
||||
DEBUG(net, 0, "Send failed: %s", err.AsString());
|
||||
this->CloseConnection();
|
||||
}
|
||||
return SPS_CLOSED;
|
||||
@@ -168,7 +169,7 @@ std::unique_ptr<Packet> NetworkTCPSocketHandler::ReceivePacket()
|
||||
NetworkError err = NetworkError::GetLast();
|
||||
if (!err.WouldBlock()) {
|
||||
/* Something went wrong... */
|
||||
if (!err.IsConnectionReset()) DEBUG(net, 0, "recv failed with error %s", err.AsString());
|
||||
if (!err.IsConnectionReset()) DEBUG(net, 0, "Recv failed: %s", err.AsString());
|
||||
this->CloseConnection();
|
||||
return nullptr;
|
||||
}
|
||||
@@ -197,7 +198,7 @@ std::unique_ptr<Packet> NetworkTCPSocketHandler::ReceivePacket()
|
||||
NetworkError err = NetworkError::GetLast();
|
||||
if (!err.WouldBlock()) {
|
||||
/* Something went wrong... */
|
||||
if (!err.IsConnectionReset()) DEBUG(net, 0, "recv failed with error %s", err.AsString());
|
||||
if (!err.IsConnectionReset()) DEBUG(net, 0, "Recv failed: %s", err.AsString());
|
||||
this->CloseConnection();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,12 @@
|
||||
#include "address.h"
|
||||
#include "packet.h"
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
/** The states of sending the packets. */
|
||||
enum SendPacketsState {
|
||||
@@ -73,23 +76,44 @@ public:
|
||||
*/
|
||||
class TCPConnecter {
|
||||
private:
|
||||
std::atomic<bool> connected;///< Whether we succeeded in making the connection
|
||||
std::atomic<bool> aborted; ///< Whether we bailed out (i.e. connection making failed)
|
||||
bool killed; ///< Whether we got killed
|
||||
SOCKET sock; ///< The socket we're connecting with
|
||||
/**
|
||||
* The current status of the connecter.
|
||||
*
|
||||
* We track the status like this to ensure everything is executed from the
|
||||
* game-thread, and not at another random time where we might not have the
|
||||
* lock on the game-state.
|
||||
*/
|
||||
enum class Status {
|
||||
INIT, ///< TCPConnecter is created but resolving hasn't started.
|
||||
RESOLVING, ///< The hostname is being resolved (threaded).
|
||||
FAILURE, ///< Resolving failed.
|
||||
CONNECTING, ///< We are currently connecting.
|
||||
};
|
||||
|
||||
void Connect();
|
||||
std::thread resolve_thread; ///< Thread used during resolving.
|
||||
std::atomic<Status> status = Status::INIT; ///< The current status of the connecter.
|
||||
|
||||
static void ThreadEntry(TCPConnecter *param);
|
||||
addrinfo *ai = nullptr; ///< getaddrinfo() allocated linked-list of resolved addresses.
|
||||
std::vector<addrinfo *> addresses; ///< Addresses we can connect to.
|
||||
std::map<SOCKET, NetworkAddress> sock_to_address; ///< Mapping of a socket to the real address it is connecting to. USed for DEBUG statements.
|
||||
size_t current_address = 0; ///< Current index in addresses we are trying.
|
||||
|
||||
protected:
|
||||
/** Address we're connecting to */
|
||||
NetworkAddress address;
|
||||
std::vector<SOCKET> sockets; ///< Pending connect() attempts.
|
||||
std::chrono::steady_clock::time_point last_attempt; ///< Time we last tried to connect.
|
||||
|
||||
std::string connection_string; ///< Current address we are connecting to (before resolving).
|
||||
|
||||
void Resolve();
|
||||
void OnResolved(addrinfo *ai);
|
||||
bool TryNextAddress();
|
||||
void Connect(addrinfo *address);
|
||||
bool CheckActivity();
|
||||
|
||||
static void ResolveThunk(TCPConnecter *connecter);
|
||||
|
||||
public:
|
||||
TCPConnecter(const std::string &connection_string, uint16 default_port);
|
||||
/** Silence the warnings */
|
||||
virtual ~TCPConnecter() {}
|
||||
virtual ~TCPConnecter();
|
||||
|
||||
/**
|
||||
* Callback when the connection succeeded.
|
||||
|
||||
@@ -41,7 +41,7 @@ NetworkAdminSocketHandler::~NetworkAdminSocketHandler()
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::CloseConnection(bool error)
|
||||
{
|
||||
delete this;
|
||||
return NETWORK_RECV_STATUS_CONN_LOST;
|
||||
return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,9 +93,9 @@ NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p)
|
||||
|
||||
default:
|
||||
if (this->HasClientQuit()) {
|
||||
DEBUG(net, 0, "[tcp/admin] received invalid packet type %d from '%s' (%s)", type, this->admin_name, this->admin_version);
|
||||
DEBUG(net, 0, "[tcp/admin] Received invalid packet type %d from '%s' (%s)", type, this->admin_name, this->admin_version);
|
||||
} else {
|
||||
DEBUG(net, 0, "[tcp/admin] received illegal packet from '%s' (%s)", this->admin_name, this->admin_version);
|
||||
DEBUG(net, 0, "[tcp/admin] Received illegal packet from '%s' (%s)", this->admin_name, this->admin_version);
|
||||
}
|
||||
|
||||
this->CloseConnection();
|
||||
@@ -128,7 +128,7 @@ NetworkRecvStatus NetworkAdminSocketHandler::ReceivePackets()
|
||||
*/
|
||||
NetworkRecvStatus NetworkAdminSocketHandler::ReceiveInvalidPacket(PacketAdminType type)
|
||||
{
|
||||
DEBUG(net, 0, "[tcp/admin] received illegal packet type %d from admin %s (%s)", type, this->admin_name, this->admin_version);
|
||||
DEBUG(net, 0, "[tcp/admin] Received illegal packet type %d from admin %s (%s)", type, this->admin_name, this->admin_version);
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "tcp.h"
|
||||
#include "../network_internal.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/** List of connections that are currently being created */
|
||||
@@ -24,38 +26,325 @@ static std::vector<TCPConnecter *> _tcp_connecters;
|
||||
* Create a new connecter for the given address
|
||||
* @param connection_string the address to connect to
|
||||
*/
|
||||
TCPConnecter::TCPConnecter(const std::string &connection_string, uint16 default_port) :
|
||||
connected(false),
|
||||
aborted(false),
|
||||
killed(false),
|
||||
sock(INVALID_SOCKET)
|
||||
TCPConnecter::TCPConnecter(const std::string &connection_string, uint16 default_port)
|
||||
{
|
||||
this->address = ParseConnectionString(connection_string, default_port);
|
||||
this->connection_string = NormalizeConnectionString(connection_string, default_port);
|
||||
|
||||
_tcp_connecters.push_back(this);
|
||||
if (!StartNewThread(nullptr, "ottd:tcp", &TCPConnecter::ThreadEntry, this)) {
|
||||
this->Connect();
|
||||
}
|
||||
}
|
||||
|
||||
/** The actual connection function */
|
||||
void TCPConnecter::Connect()
|
||||
TCPConnecter::~TCPConnecter()
|
||||
{
|
||||
this->sock = this->address.Connect();
|
||||
if (this->sock == INVALID_SOCKET) {
|
||||
this->aborted = true;
|
||||
} else {
|
||||
this->connected = true;
|
||||
if (this->resolve_thread.joinable()) {
|
||||
this->resolve_thread.join();
|
||||
}
|
||||
|
||||
for (const auto &socket : this->sockets) {
|
||||
closesocket(socket);
|
||||
}
|
||||
this->sockets.clear();
|
||||
this->sock_to_address.clear();
|
||||
|
||||
freeaddrinfo(this->ai);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point for the new threads.
|
||||
* @param param the TCPConnecter instance to call Connect on.
|
||||
* Start a connection to the indicated address.
|
||||
* @param address The address to connection to.
|
||||
*/
|
||||
/* static */ void TCPConnecter::ThreadEntry(TCPConnecter *param)
|
||||
void TCPConnecter::Connect(addrinfo *address)
|
||||
{
|
||||
param->Connect();
|
||||
SOCKET sock = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
DEBUG(net, 0, "Could not create %s %s socket: %s", NetworkAddress::SocketTypeAsString(address->ai_socktype), NetworkAddress::AddressFamilyAsString(address->ai_family), NetworkError::GetLast().AsString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SetNoDelay(sock)) {
|
||||
DEBUG(net, 1, "Setting TCP_NODELAY failed: %s", NetworkError::GetLast().AsString());
|
||||
}
|
||||
if (!SetNonBlocking(sock)) {
|
||||
DEBUG(net, 0, "Setting non-blocking mode failed: %s", NetworkError::GetLast().AsString());
|
||||
}
|
||||
|
||||
NetworkAddress network_address = NetworkAddress(address->ai_addr, (int)address->ai_addrlen);
|
||||
DEBUG(net, 5, "Attempting to connect to %s", network_address.GetAddressAsString().c_str());
|
||||
|
||||
int err = connect(sock, address->ai_addr, (int)address->ai_addrlen);
|
||||
if (err != 0 && !NetworkError::GetLast().IsConnectInProgress()) {
|
||||
closesocket(sock);
|
||||
|
||||
DEBUG(net, 1, "Could not connect to %s: %s", network_address.GetAddressAsString().c_str(), NetworkError::GetLast().AsString());
|
||||
return;
|
||||
}
|
||||
|
||||
this->sock_to_address[sock] = network_address;
|
||||
this->sockets.push_back(sock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the connect() for the next address in the list.
|
||||
* @return True iff a new connect() is attempted.
|
||||
*/
|
||||
bool TCPConnecter::TryNextAddress()
|
||||
{
|
||||
if (this->current_address >= this->addresses.size()) return false;
|
||||
|
||||
this->last_attempt = std::chrono::steady_clock::now();
|
||||
this->Connect(this->addresses[this->current_address++]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback when resolving is done.
|
||||
* @param ai A linked-list of address information.
|
||||
*/
|
||||
void TCPConnecter::OnResolved(addrinfo *ai)
|
||||
{
|
||||
std::deque<addrinfo *> addresses_ipv4, addresses_ipv6;
|
||||
|
||||
/* Apply "Happy Eyeballs" if it is likely IPv6 is functional. */
|
||||
|
||||
/* Detect if IPv6 is likely to succeed or not. */
|
||||
bool seen_ipv6 = false;
|
||||
bool resort = true;
|
||||
for (addrinfo *runp = ai; runp != nullptr; runp = runp->ai_next) {
|
||||
if (runp->ai_family == AF_INET6) {
|
||||
seen_ipv6 = true;
|
||||
} else if (!seen_ipv6) {
|
||||
/* We see an IPv4 before an IPv6; this most likely means there is
|
||||
* no IPv6 available on the system, so keep the order of this
|
||||
* list. */
|
||||
resort = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert the addrinfo into NetworkAddresses. */
|
||||
for (addrinfo *runp = ai; runp != nullptr; runp = runp->ai_next) {
|
||||
if (resort) {
|
||||
if (runp->ai_family == AF_INET6) {
|
||||
addresses_ipv6.emplace_back(runp);
|
||||
} else {
|
||||
addresses_ipv4.emplace_back(runp);
|
||||
}
|
||||
} else {
|
||||
this->addresses.emplace_back(runp);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we want to resort, make the list like IPv6 / IPv4 / IPv6 / IPv4 / ..
|
||||
* for how ever many (round-robin) DNS entries we have. */
|
||||
if (resort) {
|
||||
while (!addresses_ipv4.empty() || !addresses_ipv6.empty()) {
|
||||
if (!addresses_ipv6.empty()) {
|
||||
this->addresses.push_back(addresses_ipv6.front());
|
||||
addresses_ipv6.pop_front();
|
||||
}
|
||||
if (!addresses_ipv4.empty()) {
|
||||
this->addresses.push_back(addresses_ipv4.front());
|
||||
addresses_ipv4.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_debug_net_level >= 6) {
|
||||
DEBUG(net, 6, "%s resolved in:", this->connection_string.c_str());
|
||||
for (const auto &address : this->addresses) {
|
||||
DEBUG(net, 6, "- %s", NetworkAddress(address->ai_addr, (int)address->ai_addrlen).GetAddressAsString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
this->current_address = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start resolving the hostname.
|
||||
*
|
||||
* This function must change "status" to either Status::FAILURE
|
||||
* or Status::CONNECTING before returning.
|
||||
*/
|
||||
void TCPConnecter::Resolve()
|
||||
{
|
||||
/* Port is already guaranteed part of the connection_string. */
|
||||
NetworkAddress address = ParseConnectionString(this->connection_string, 0);
|
||||
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
char port_name[6];
|
||||
seprintf(port_name, lastof(port_name), "%u", address.GetPort());
|
||||
|
||||
static bool getaddrinfo_timeout_error_shown = false;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
addrinfo *ai;
|
||||
int error = getaddrinfo(address.GetHostname(), port_name, &hints, &ai);
|
||||
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::seconds>(end - start);
|
||||
if (!getaddrinfo_timeout_error_shown && duration >= std::chrono::seconds(5)) {
|
||||
DEBUG(net, 0, "getaddrinfo() for address \"%s\" took %i seconds", this->connection_string.c_str(), (int)duration.count());
|
||||
DEBUG(net, 0, " This is likely an issue in the DNS name resolver's configuration causing it to time out");
|
||||
getaddrinfo_timeout_error_shown = true;
|
||||
}
|
||||
|
||||
if (error != 0) {
|
||||
DEBUG(net, 0, "Failed to resolve DNS for %s", this->connection_string.c_str());
|
||||
this->status = Status::FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
this->ai = ai;
|
||||
this->OnResolved(ai);
|
||||
|
||||
this->status = Status::CONNECTING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thunk to start Resolve() on the right instance.
|
||||
*/
|
||||
/* static */ void TCPConnecter::ResolveThunk(TCPConnecter *connecter)
|
||||
{
|
||||
connecter->Resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there was activity for this connecter.
|
||||
* @return True iff the TCPConnecter is done and can be cleaned up.
|
||||
*/
|
||||
bool TCPConnecter::CheckActivity()
|
||||
{
|
||||
switch (this->status.load()) {
|
||||
case Status::INIT:
|
||||
/* Start the thread delayed, so the vtable is loaded. This allows classes
|
||||
* to overload functions used by Resolve() (in case threading is disabled). */
|
||||
if (StartNewThread(&this->resolve_thread, "ottd:resolve", &TCPConnecter::ResolveThunk, this)) {
|
||||
this->status = Status::RESOLVING;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No threads, do a blocking resolve. */
|
||||
this->Resolve();
|
||||
|
||||
/* Continue as we are either failed or can start the first
|
||||
* connection. The rest of this function handles exactly that. */
|
||||
break;
|
||||
|
||||
case Status::RESOLVING:
|
||||
/* Wait till Resolve() comes back with an answer (in case it runs threaded). */
|
||||
return false;
|
||||
|
||||
case Status::FAILURE:
|
||||
/* Ensure the OnFailure() is called from the game-thread instead of the
|
||||
* resolve-thread, as otherwise we can get into some threading issues. */
|
||||
this->OnFailure();
|
||||
return true;
|
||||
|
||||
case Status::CONNECTING:
|
||||
break;
|
||||
}
|
||||
|
||||
/* If there are no attempts pending, connect to the next. */
|
||||
if (this->sockets.empty()) {
|
||||
if (!this->TryNextAddress()) {
|
||||
/* There were no more addresses to try, so we failed. */
|
||||
this->OnFailure();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fd_set write_fd;
|
||||
FD_ZERO(&write_fd);
|
||||
for (const auto &socket : this->sockets) {
|
||||
FD_SET(socket, &write_fd);
|
||||
}
|
||||
|
||||
timeval tv;
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = 0;
|
||||
int n = select(FD_SETSIZE, NULL, &write_fd, NULL, &tv);
|
||||
/* select() failed; hopefully next try it doesn't. */
|
||||
if (n < 0) {
|
||||
/* select() normally never fails; so hopefully it works next try! */
|
||||
DEBUG(net, 1, "select() failed: %s", NetworkError::GetLast().AsString());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No socket updates. */
|
||||
if (n == 0) {
|
||||
/* Wait 250ms between attempting another address. */
|
||||
if (std::chrono::steady_clock::now() < this->last_attempt + std::chrono::milliseconds(250)) return false;
|
||||
|
||||
/* Try the next address in the list. */
|
||||
if (this->TryNextAddress()) return false;
|
||||
|
||||
/* Wait up to 3 seconds since the last connection we started. */
|
||||
if (std::chrono::steady_clock::now() < this->last_attempt + std::chrono::milliseconds(3000)) return false;
|
||||
|
||||
/* More than 3 seconds no socket reported activity, and there are no
|
||||
* more address to try. Timeout the attempt. */
|
||||
DEBUG(net, 0, "Timeout while connecting to %s", this->connection_string.c_str());
|
||||
|
||||
for (const auto &socket : this->sockets) {
|
||||
closesocket(socket);
|
||||
}
|
||||
this->sockets.clear();
|
||||
this->sock_to_address.clear();
|
||||
|
||||
this->OnFailure();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check for errors on any of the sockets. */
|
||||
for (auto it = this->sockets.begin(); it != this->sockets.end(); /* nothing */) {
|
||||
NetworkError socket_error = GetSocketError(*it);
|
||||
if (socket_error.HasError()) {
|
||||
DEBUG(net, 1, "Could not connect to %s: %s", this->sock_to_address[*it].GetAddressAsString().c_str(), socket_error.AsString());
|
||||
closesocket(*it);
|
||||
this->sock_to_address.erase(*it);
|
||||
it = this->sockets.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
/* In case all sockets had an error, queue a new one. */
|
||||
if (this->sockets.empty()) {
|
||||
if (!this->TryNextAddress()) {
|
||||
/* There were no more addresses to try, so we failed. */
|
||||
this->OnFailure();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* At least one socket is connected. The first one that does is the one
|
||||
* we will be using, and we close all other sockets. */
|
||||
SOCKET connected_socket = INVALID_SOCKET;
|
||||
for (auto it = this->sockets.begin(); it != this->sockets.end(); /* nothing */) {
|
||||
if (connected_socket == INVALID_SOCKET && FD_ISSET(*it, &write_fd)) {
|
||||
connected_socket = *it;
|
||||
} else {
|
||||
closesocket(*it);
|
||||
}
|
||||
this->sock_to_address.erase(*it);
|
||||
it = this->sockets.erase(it);
|
||||
}
|
||||
assert(connected_socket != INVALID_SOCKET);
|
||||
|
||||
DEBUG(net, 3, "Connected to %s", this->connection_string.c_str());
|
||||
if (_debug_net_level >= 5) {
|
||||
DEBUG(net, 5, "- using %s", NetworkAddress::GetPeerName(connected_socket).c_str());
|
||||
}
|
||||
|
||||
this->OnConnect(connected_socket);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,32 +357,22 @@ void TCPConnecter::Connect()
|
||||
{
|
||||
for (auto iter = _tcp_connecters.begin(); iter < _tcp_connecters.end(); /* nothing */) {
|
||||
TCPConnecter *cur = *iter;
|
||||
const bool connected = cur->connected.load();
|
||||
const bool aborted = cur->aborted.load();
|
||||
if ((connected || aborted) && cur->killed) {
|
||||
|
||||
if (cur->CheckActivity()) {
|
||||
iter = _tcp_connecters.erase(iter);
|
||||
if (cur->sock != INVALID_SOCKET) closesocket(cur->sock);
|
||||
delete cur;
|
||||
continue;
|
||||
} else {
|
||||
iter++;
|
||||
}
|
||||
if (connected) {
|
||||
iter = _tcp_connecters.erase(iter);
|
||||
cur->OnConnect(cur->sock);
|
||||
delete cur;
|
||||
continue;
|
||||
}
|
||||
if (aborted) {
|
||||
iter = _tcp_connecters.erase(iter);
|
||||
cur->OnFailure();
|
||||
delete cur;
|
||||
continue;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
/** Kill all connection attempts. */
|
||||
/* static */ void TCPConnecter::KillAll()
|
||||
{
|
||||
for (TCPConnecter *conn : _tcp_connecters) conn->killed = true;
|
||||
for (auto iter = _tcp_connecters.begin(); iter < _tcp_connecters.end(); /* nothing */) {
|
||||
TCPConnecter *cur = *iter;
|
||||
iter = _tcp_connecters.erase(iter);
|
||||
delete cur;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,9 +137,11 @@ const char *ContentInfo::GetTextfile(TextfileType type) const
|
||||
return ::GetTextfile(type, GetContentInfoSubDir(this->type), tmp);
|
||||
}
|
||||
|
||||
void NetworkContentSocketHandler::Close()
|
||||
/**
|
||||
* Close the actual socket.
|
||||
*/
|
||||
void NetworkContentSocketHandler::CloseSocket()
|
||||
{
|
||||
CloseConnection();
|
||||
if (this->sock == INVALID_SOCKET) return;
|
||||
|
||||
closesocket(this->sock);
|
||||
@@ -167,9 +169,9 @@ bool NetworkContentSocketHandler::HandlePacket(Packet *p)
|
||||
|
||||
default:
|
||||
if (this->HasClientQuit()) {
|
||||
DEBUG(net, 0, "[tcp/content] received invalid packet type %d", type);
|
||||
DEBUG(net, 0, "[tcp/content] Received invalid packet type %d", type);
|
||||
} else {
|
||||
DEBUG(net, 0, "[tcp/content] received illegal packet");
|
||||
DEBUG(net, 0, "[tcp/content] Received illegal packet");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -219,7 +221,7 @@ bool NetworkContentSocketHandler::ReceivePackets()
|
||||
*/
|
||||
bool NetworkContentSocketHandler::ReceiveInvalidPacket(PacketContentType type)
|
||||
{
|
||||
DEBUG(net, 0, "[tcp/content] received illegal packet type %d", type);
|
||||
DEBUG(net, 0, "[tcp/content] Received illegal packet type %d", type);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
/** Base socket handler for all Content TCP sockets */
|
||||
class NetworkContentSocketHandler : public NetworkTCPSocketHandler {
|
||||
protected:
|
||||
void Close() override;
|
||||
void CloseSocket();
|
||||
|
||||
bool ReceiveInvalidPacket(PacketContentType type);
|
||||
|
||||
@@ -128,7 +128,11 @@ public:
|
||||
}
|
||||
|
||||
/** On destructing of this class, the socket needs to be closed */
|
||||
virtual ~NetworkContentSocketHandler() { this->Close(); }
|
||||
virtual ~NetworkContentSocketHandler()
|
||||
{
|
||||
/* Virtual functions get called statically in destructors, so make it explicit to remove any confusion. */
|
||||
this->CloseSocket();
|
||||
}
|
||||
|
||||
bool ReceivePackets();
|
||||
};
|
||||
|
||||
@@ -102,7 +102,7 @@ NetworkGameSocketHandler::NetworkGameSocketHandler(SOCKET s) : info(nullptr), cl
|
||||
*/
|
||||
NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool error)
|
||||
{
|
||||
if (this->ignore_close) return NETWORK_RECV_STATUS_CONN_LOST;
|
||||
if (this->ignore_close) return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||
|
||||
/* Clients drop back to the main menu */
|
||||
if (!_network_server && _networking) {
|
||||
@@ -112,10 +112,10 @@ NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool error)
|
||||
_networking = false;
|
||||
ShowErrorMessage(STR_NETWORK_ERROR_LOSTCONNECTION, INVALID_STRING_ID, WL_CRITICAL);
|
||||
|
||||
return NETWORK_RECV_STATUS_CONN_LOST;
|
||||
return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||
}
|
||||
|
||||
return this->CloseConnection(error ? NETWORK_RECV_STATUS_SERVER_ERROR : NETWORK_RECV_STATUS_CONN_LOST);
|
||||
return this->CloseConnection(NETWORK_RECV_STATUS_CONNECTION_LOST);
|
||||
}
|
||||
|
||||
|
||||
@@ -190,9 +190,9 @@ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet *p)
|
||||
this->CloseConnection();
|
||||
|
||||
if (this->HasClientQuit()) {
|
||||
DEBUG(net, 0, "[tcp/game] received invalid packet type %d from client %d", type, this->client_id);
|
||||
DEBUG(net, 0, "[tcp/game] Received invalid packet type %d from client %d", type, this->client_id);
|
||||
} else {
|
||||
DEBUG(net, 0, "[tcp/game] received illegal packet from client %d", this->client_id);
|
||||
DEBUG(net, 0, "[tcp/game] Received illegal packet from client %d", this->client_id);
|
||||
}
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
@@ -223,7 +223,7 @@ NetworkRecvStatus NetworkGameSocketHandler::ReceivePackets()
|
||||
*/
|
||||
NetworkRecvStatus NetworkGameSocketHandler::ReceiveInvalidPacket(PacketGameType type)
|
||||
{
|
||||
DEBUG(net, 0, "[tcp/game] received illegal packet type %d from client %d", type, this->client_id);
|
||||
DEBUG(net, 0, "[tcp/game] Received illegal packet type %d from client %d", type, this->client_id);
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ NetworkHTTPSocketHandler::NetworkHTTPSocketHandler(SOCKET s,
|
||||
size_t bufferSize = strlen(url) + strlen(host) + strlen(_openttd_revision) + (data == nullptr ? 0 : strlen(data)) + 128;
|
||||
char *buffer = AllocaM(char, bufferSize);
|
||||
|
||||
DEBUG(net, 7, "[tcp/http] requesting %s%s", host, url);
|
||||
DEBUG(net, 5, "[tcp/http] Requesting %s%s", host, url);
|
||||
if (data != nullptr) {
|
||||
seprintf(buffer, buffer + bufferSize - 1, "POST %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: OpenTTD/%s\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s\r\n", url, host, _openttd_revision, (int)strlen(data), data);
|
||||
} else {
|
||||
@@ -85,7 +85,7 @@ NetworkRecvStatus NetworkHTTPSocketHandler::CloseConnection(bool error)
|
||||
* Helper to simplify the error handling.
|
||||
* @param msg the error message to show.
|
||||
*/
|
||||
#define return_error(msg) { DEBUG(net, 0, msg); return -1; }
|
||||
#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
|
||||
@@ -112,7 +112,7 @@ int NetworkHTTPSocketHandler::HandleHeader()
|
||||
/* 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");
|
||||
return_error("[tcp/http] Received invalid HTTP reply");
|
||||
}
|
||||
|
||||
char *status = this->recv_buffer + strlen(HTTP_1_0);
|
||||
@@ -121,7 +121,7 @@ int NetworkHTTPSocketHandler::HandleHeader()
|
||||
|
||||
/* 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");
|
||||
if (length == nullptr) return_error("[tcp/http] Missing 'content-length' header");
|
||||
|
||||
/* Skip the header */
|
||||
length += strlen(CONTENT_LENGTH);
|
||||
@@ -139,9 +139,9 @@ int NetworkHTTPSocketHandler::HandleHeader()
|
||||
/* 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");
|
||||
if (len == 0) return_error("[tcp/http] Refusing to download 0 bytes");
|
||||
|
||||
DEBUG(net, 7, "[tcp/http] downloading %i bytes", len);
|
||||
DEBUG(net, 7, "[tcp/http] Downloading %i bytes", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -154,15 +154,15 @@ int NetworkHTTPSocketHandler::HandleHeader()
|
||||
/* Search the end of the line. This is safe because the header will
|
||||
* always end with two newlines. */
|
||||
*strstr(status, NEWLINE) = '\0';
|
||||
DEBUG(net, 0, "[tcp/http] unhandled status reply %s", status);
|
||||
DEBUG(net, 1, "[tcp/http] Unhandled status reply %s", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (this->redirect_depth == 5) return_error("[tcp/http] too many redirects, looping redirects?");
|
||||
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");
|
||||
if (uri == nullptr) return_error("[tcp/http] Missing 'location' header for redirect");
|
||||
|
||||
uri += strlen(LOCATION);
|
||||
|
||||
@@ -171,7 +171,7 @@ int NetworkHTTPSocketHandler::HandleHeader()
|
||||
char *end_of_line = strstr(uri, NEWLINE);
|
||||
*end_of_line = '\0';
|
||||
|
||||
DEBUG(net, 6, "[tcp/http] redirecting to %s", uri);
|
||||
DEBUG(net, 7, "[tcp/http] Redirecting to %s", uri);
|
||||
|
||||
int ret = NetworkHTTPSocketHandler::Connect(uri, this->callback, this->data, this->redirect_depth + 1);
|
||||
if (ret != 0) return ret;
|
||||
@@ -194,18 +194,20 @@ int NetworkHTTPSocketHandler::HandleHeader()
|
||||
/* 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");
|
||||
if (hname == nullptr) return_error("[tcp/http] Invalid location");
|
||||
|
||||
hname += 3;
|
||||
|
||||
char *url = strchr(hname, '/');
|
||||
if (url == nullptr) return_error("[tcp/http] invalid location");
|
||||
if (url == nullptr) return_error("[tcp/http] Invalid location");
|
||||
|
||||
*url = '\0';
|
||||
|
||||
std::string hostname = std::string(hname);
|
||||
|
||||
/* Restore the URL. */
|
||||
*url = '/';
|
||||
new NetworkHTTPContentConnecter(hname, callback, url, data, depth);
|
||||
new NetworkHTTPContentConnecter(hostname, callback, url, data, depth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -226,7 +228,7 @@ int NetworkHTTPSocketHandler::Receive()
|
||||
NetworkError err = NetworkError::GetLast();
|
||||
if (!err.WouldBlock()) {
|
||||
/* Something went wrong... */
|
||||
if (!err.IsConnectionReset()) DEBUG(net, 0, "recv failed with error %s", err.AsString());
|
||||
if (!err.IsConnectionReset()) DEBUG(net, 0, "Recv failed: %s", err.AsString());
|
||||
return -1;
|
||||
}
|
||||
/* Connection would block, so stop for now */
|
||||
@@ -254,7 +256,7 @@ int NetworkHTTPSocketHandler::Receive()
|
||||
|
||||
if (end_of_header == nullptr) {
|
||||
if (read == lengthof(this->recv_buffer)) {
|
||||
DEBUG(net, 0, "[tcp/http] header too big");
|
||||
DEBUG(net, 1, "[tcp/http] Header too big");
|
||||
return -1;
|
||||
}
|
||||
this->recv_pos = read;
|
||||
|
||||
@@ -73,6 +73,7 @@ public:
|
||||
|
||||
/** 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
|
||||
@@ -81,14 +82,15 @@ class NetworkHTTPContentConnecter : TCPConnecter {
|
||||
public:
|
||||
/**
|
||||
* Start the connecting.
|
||||
* @param connection_string The address to connect to.
|
||||
* @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 &connection_string, HTTPCallback *callback, const char *url, const char *data = nullptr, int depth = 0) :
|
||||
TCPConnecter(connection_string, 80),
|
||||
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),
|
||||
@@ -110,7 +112,7 @@ public:
|
||||
|
||||
void OnConnect(SOCKET s) override
|
||||
{
|
||||
new NetworkHTTPSocketHandler(s, this->callback, this->address.GetHostname(), this->url, this->data, this->depth);
|
||||
new NetworkHTTPSocketHandler(s, this->callback, this->hostname.c_str(), this->url, this->data, this->depth);
|
||||
/* We've relinquished control of data now. */
|
||||
this->data = nullptr;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
SetNonBlocking(s); // XXX error handling?
|
||||
|
||||
NetworkAddress address(sin, sin_len);
|
||||
DEBUG(net, 1, "[%s] Client connected from %s on frame %d", Tsocket::GetName(), address.GetHostname(), _frame_counter);
|
||||
DEBUG(net, 3, "[%s] Client connected from %s on frame %d", Tsocket::GetName(), address.GetHostname(), _frame_counter);
|
||||
|
||||
SetNoDelay(s); // XXX error handling?
|
||||
|
||||
@@ -61,10 +61,10 @@ public:
|
||||
Packet p(Tban_packet);
|
||||
p.PrepareToSend();
|
||||
|
||||
DEBUG(net, 1, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), entry.c_str());
|
||||
DEBUG(net, 2, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), entry.c_str());
|
||||
|
||||
if (p.TransferOut<int>(send, s, 0) < 0) {
|
||||
DEBUG(net, 0, "send failed with error %s", NetworkError::GetLast().AsString());
|
||||
DEBUG(net, 0, "[%s] send failed: %s", Tsocket::GetName(), NetworkError::GetLast().AsString());
|
||||
}
|
||||
closesocket(s);
|
||||
break;
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
p.PrepareToSend();
|
||||
|
||||
if (p.TransferOut<int>(send, s, 0) < 0) {
|
||||
DEBUG(net, 0, "send failed with error %s", NetworkError::GetLast().AsString());
|
||||
DEBUG(net, 0, "[%s] send failed: %s", Tsocket::GetName(), NetworkError::GetLast().AsString());
|
||||
}
|
||||
closesocket(s);
|
||||
|
||||
@@ -150,7 +150,7 @@ public:
|
||||
}
|
||||
|
||||
if (sockets.size() == 0) {
|
||||
DEBUG(net, 0, "[server] could not start network: could not create listening socket");
|
||||
DEBUG(net, 0, "Could not start network: could not create listening socket");
|
||||
ShowNetworkError(STR_NETWORK_ERROR_SERVER_START);
|
||||
return false;
|
||||
}
|
||||
@@ -165,7 +165,7 @@ public:
|
||||
closesocket(s.second);
|
||||
}
|
||||
sockets.clear();
|
||||
DEBUG(net, 1, "[%s] closed listeners", Tsocket::GetName());
|
||||
DEBUG(net, 5, "[%s] Closed listeners", Tsocket::GetName());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -127,16 +127,16 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a
|
||||
/* Enable broadcast */
|
||||
unsigned long val = 1;
|
||||
if (setsockopt(s.second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) {
|
||||
DEBUG(net, 1, "[udp] setting broadcast failed with: %s", NetworkError::GetLast().AsString());
|
||||
DEBUG(net, 1, "Setting broadcast mode failed: %s", NetworkError::GetLast().AsString());
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the buffer */
|
||||
ssize_t res = p->TransferOut<int>(sendto, s.second, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength());
|
||||
DEBUG(net, 7, "[udp] sendto(%s)", NetworkAddressDumper().GetAddressAsString(&send));
|
||||
DEBUG(net, 7, "sendto(%s)", NetworkAddressDumper().GetAddressAsString(&send));
|
||||
|
||||
/* Check for any errors, but ignore it otherwise */
|
||||
if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %s", NetworkAddressDumper().GetAddressAsString(&send), NetworkError::GetLast().AsString());
|
||||
if (res == -1) DEBUG(net, 1, "sendto(%s) failed with: %s", NetworkAddressDumper().GetAddressAsString(&send), NetworkError::GetLast().AsString());
|
||||
|
||||
if (!all) break;
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ public:
|
||||
virtual ~NetworkUDPSocketHandler() { this->Close(); }
|
||||
|
||||
bool Listen();
|
||||
void Close() override;
|
||||
void Close();
|
||||
|
||||
void SendPacket(Packet *p, NetworkAddress *recv, bool all = false, bool broadcast = false, bool short_mtu = false);
|
||||
void ReceivePackets();
|
||||
|
||||
@@ -288,7 +288,7 @@ void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send,
|
||||
|
||||
DEBUG(desync, 1, "msg: date{%08x; %02x; %02x}; %s", _date, _date_fract, _tick_skip_counter, message);
|
||||
IConsolePrintF(colour, "%s", message);
|
||||
NetworkAddChatMessage((TextColour)colour, _settings_client.gui.network_chat_timeout, "%s", message);
|
||||
NetworkAddChatMessage((TextColour)colour, _settings_client.gui.network_chat_timeout, message);
|
||||
}
|
||||
|
||||
/* Calculate the frame-lag of a client */
|
||||
@@ -527,6 +527,19 @@ std::string_view ParseFullConnectionString(const std::string &connection_string,
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a connection string. That is, ensure there is a port in the string.
|
||||
* @param connection_string The connection string to normalize.
|
||||
* @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)
|
||||
{
|
||||
uint16 port = default_port;
|
||||
std::string_view ip = ParseFullConnectionString(connection_string, port);
|
||||
return std::string(ip) + ":" + std::to_string(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string containing either "hostname" or "hostname:ip" to a
|
||||
* NetworkAddress.
|
||||
@@ -598,13 +611,13 @@ void NetworkClose(bool close_admins)
|
||||
}
|
||||
|
||||
for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
|
||||
cs->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
||||
cs->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
|
||||
}
|
||||
ServerNetworkGameSocketHandler::CloseListeners();
|
||||
ServerNetworkAdminSocketHandler::CloseListeners();
|
||||
} else if (MyClient::my_client != nullptr) {
|
||||
MyClient::SendQuit();
|
||||
MyClient::my_client->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
||||
MyClient::my_client->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
|
||||
}
|
||||
|
||||
TCPConnecter::KillAll();
|
||||
@@ -636,41 +649,77 @@ static void NetworkInitialize(bool close_admins = true)
|
||||
_last_sync_tick_skip_counter = 0;
|
||||
}
|
||||
|
||||
/** Non blocking connection create to query servers */
|
||||
/** Non blocking connection to query servers for their game info. */
|
||||
class TCPQueryConnecter : TCPConnecter {
|
||||
private:
|
||||
bool request_company_info;
|
||||
std::string connection_string;
|
||||
|
||||
public:
|
||||
TCPQueryConnecter(const std::string &connection_string, bool request_company_info) : TCPConnecter(connection_string, NETWORK_DEFAULT_PORT), request_company_info(request_company_info), connection_string(connection_string) {}
|
||||
TCPQueryConnecter(const std::string &connection_string) : TCPConnecter(connection_string, NETWORK_DEFAULT_PORT), connection_string(connection_string) {}
|
||||
|
||||
void OnFailure() override
|
||||
{
|
||||
NetworkDisconnect();
|
||||
NetworkGameList *item = NetworkGameListAddItem(connection_string);
|
||||
item->online = false;
|
||||
|
||||
UpdateNetworkGameWindow();
|
||||
}
|
||||
|
||||
void OnConnect(SOCKET s) override
|
||||
{
|
||||
_networking = true;
|
||||
new ClientNetworkGameSocketHandler(s, this->connection_string);
|
||||
MyClient::SendInformationQuery(request_company_info);
|
||||
MyClient::SendInformationQuery(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Query a server to fetch his game-info.
|
||||
* Query a server to fetch the game-info.
|
||||
* @param connection_string the address to query.
|
||||
* @param request_company_info Whether to request company info too.
|
||||
*/
|
||||
void NetworkTCPQueryServer(const std::string &connection_string, bool request_company_info)
|
||||
void NetworkQueryServer(const std::string &connection_string)
|
||||
{
|
||||
if (!_network_available) return;
|
||||
|
||||
NetworkDisconnect();
|
||||
NetworkInitialize();
|
||||
|
||||
new TCPQueryConnecter(connection_string, request_company_info);
|
||||
new TCPQueryConnecter(connection_string);
|
||||
}
|
||||
|
||||
/** Non blocking connection to query servers for their game and company info. */
|
||||
class TCPLobbyQueryConnecter : TCPConnecter {
|
||||
private:
|
||||
std::string connection_string;
|
||||
|
||||
public:
|
||||
TCPLobbyQueryConnecter(const std::string &connection_string) : TCPConnecter(connection_string, NETWORK_DEFAULT_PORT), connection_string(connection_string) {}
|
||||
|
||||
void OnFailure() override
|
||||
{
|
||||
DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
|
||||
|
||||
ShowErrorMessage(STR_NETWORK_ERROR_NOCONNECTION, INVALID_STRING_ID, WL_ERROR);
|
||||
}
|
||||
|
||||
void OnConnect(SOCKET s) override
|
||||
{
|
||||
_networking = true;
|
||||
new ClientNetworkGameSocketHandler(s, this->connection_string);
|
||||
MyClient::SendInformationQuery(true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Query a server to fetch his game-info for the lobby.
|
||||
* @param connection_string the address to query.
|
||||
*/
|
||||
void NetworkQueryLobbyServer(const std::string &connection_string)
|
||||
{
|
||||
if (!_network_available) return;
|
||||
|
||||
NetworkInitialize();
|
||||
|
||||
new TCPLobbyQueryConnecter(connection_string);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -680,7 +729,7 @@ void NetworkTCPQueryServer(const std::string &connection_string, bool request_co
|
||||
* @param connection_string The IP:port of the server to add.
|
||||
* @return The entry on the game list.
|
||||
*/
|
||||
NetworkGameList *NetworkAddServer(const std::string &connection_string)
|
||||
NetworkGameList *NetworkAddServer(const std::string &connection_string, bool manually)
|
||||
{
|
||||
if (connection_string.empty()) return nullptr;
|
||||
|
||||
@@ -689,13 +738,13 @@ NetworkGameList *NetworkAddServer(const std::string &connection_string)
|
||||
if (item->info.server_name.empty()) {
|
||||
ClearGRFConfigList(&item->info.grfconfig);
|
||||
item->info.server_name = connection_string;
|
||||
item->manually = true;
|
||||
|
||||
NetworkRebuildHostList();
|
||||
UpdateNetworkGameWindow();
|
||||
|
||||
NetworkQueryServer(connection_string);
|
||||
}
|
||||
|
||||
NetworkTCPQueryServer(connection_string);
|
||||
if (manually) item->manually = true;
|
||||
|
||||
return item;
|
||||
}
|
||||
@@ -840,13 +889,13 @@ static void CheckClientAndServerName()
|
||||
{
|
||||
static const char *fallback_client_name = "Unnamed Client";
|
||||
if (StrEmpty(_settings_client.network.client_name) || strcmp(_settings_client.network.client_name, fallback_client_name) == 0) {
|
||||
DEBUG(net, 0, "No \"client_name\" has been set, using \"%s\" instead. Please set this now using the \"name <new name>\" command.", fallback_client_name);
|
||||
DEBUG(net, 1, "No \"client_name\" has been set, using \"%s\" instead. Please set this now using the \"name <new name>\" command", fallback_client_name);
|
||||
strecpy(_settings_client.network.client_name, fallback_client_name, lastof(_settings_client.network.client_name));
|
||||
}
|
||||
|
||||
static const char *fallback_server_name = "Unnamed Server";
|
||||
if (StrEmpty(_settings_client.network.server_name) || strcmp(_settings_client.network.server_name, fallback_server_name) == 0) {
|
||||
DEBUG(net, 0, "No \"server_name\" has been set, using \"%s\" instead. Please set this now using the \"server_name <new name>\" command.", fallback_server_name);
|
||||
DEBUG(net, 1, "No \"server_name\" has been set, using \"%s\" instead. Please set this now using the \"server_name <new name>\" command", fallback_server_name);
|
||||
strecpy(_settings_client.network.server_name, fallback_server_name, lastof(_settings_client.network.server_name));
|
||||
}
|
||||
}
|
||||
@@ -864,17 +913,17 @@ bool NetworkServerStart()
|
||||
|
||||
NetworkDisconnect(false, false);
|
||||
NetworkInitialize(false);
|
||||
DEBUG(net, 1, "starting listeners for clients");
|
||||
DEBUG(net, 5, "Starting listeners for clients");
|
||||
if (!ServerNetworkGameSocketHandler::Listen(_settings_client.network.server_port)) return false;
|
||||
|
||||
/* Only listen for admins when the password isn't empty. */
|
||||
if (!StrEmpty(_settings_client.network.admin_password)) {
|
||||
DEBUG(net, 1, "starting listeners for admins");
|
||||
DEBUG(net, 5, "Starting listeners for admins");
|
||||
if (!ServerNetworkAdminSocketHandler::Listen(_settings_client.network.server_admin_port)) return false;
|
||||
}
|
||||
|
||||
/* Try to start UDP-server */
|
||||
DEBUG(net, 1, "starting listeners for incoming server queries");
|
||||
DEBUG(net, 5, "Starting listeners for incoming server queries");
|
||||
NetworkUDPServerListen();
|
||||
|
||||
_network_company_states = CallocT<NetworkCompanyState>(MAX_COMPANIES);
|
||||
@@ -1026,7 +1075,7 @@ void NetworkGameLoop()
|
||||
static bool check_sync_state = false;
|
||||
static uint32 sync_state[2];
|
||||
if (f == nullptr && next_date == 0) {
|
||||
DEBUG(net, 0, "Cannot open commands.log");
|
||||
DEBUG(desync, 0, "Cannot open commands.log");
|
||||
next_date = 1;
|
||||
}
|
||||
|
||||
@@ -1107,16 +1156,16 @@ void NetworkGameLoop()
|
||||
/* A message that is not very important to the log playback, but part of the log. */
|
||||
#ifndef DEBUG_FAILED_DUMP_COMMANDS
|
||||
} else if (strncmp(p, "cmdf: ", 6) == 0) {
|
||||
DEBUG(net, 0, "Skipping replay of failed command: %s", p + 6);
|
||||
DEBUG(desync, 0, "Skipping replay of failed command: %s", p + 6);
|
||||
#endif
|
||||
} else {
|
||||
/* Can't parse a line; what's wrong here? */
|
||||
DEBUG(net, 0, "trying to parse: %s", p);
|
||||
DEBUG(desync, 0, "Trying to parse: %s", p);
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
if (f != nullptr && feof(f)) {
|
||||
DEBUG(net, 0, "End of commands.log");
|
||||
DEBUG(desync, 0, "End of commands.log");
|
||||
fclose(f);
|
||||
f = nullptr;
|
||||
}
|
||||
@@ -1195,29 +1244,36 @@ static void NetworkGenerateServerId()
|
||||
seprintf(_settings_client.network.network_id, lastof(_settings_client.network.network_id), "%s", hex_output);
|
||||
}
|
||||
|
||||
void NetworkStartDebugLog(const std::string &connection_string)
|
||||
{
|
||||
extern SOCKET _debug_socket; // Comes from debug.c
|
||||
class TCPNetworkDebugConnecter : TCPConnecter {
|
||||
private:
|
||||
std::string connection_string;
|
||||
|
||||
NetworkAddress address = ParseConnectionString(connection_string, NETWORK_DEFAULT_DEBUGLOG_PORT);
|
||||
public:
|
||||
TCPNetworkDebugConnecter(const std::string &connection_string) : TCPConnecter(connection_string, NETWORK_DEFAULT_DEBUGLOG_PORT), connection_string(connection_string) {}
|
||||
|
||||
DEBUG(net, 0, "Redirecting DEBUG() to %s", address.GetAddressAsString().c_str());
|
||||
|
||||
SOCKET s = address.Connect();
|
||||
if (s == INVALID_SOCKET) {
|
||||
DEBUG(net, 0, "Failed to open socket for redirection DEBUG()");
|
||||
return;
|
||||
void OnFailure() override
|
||||
{
|
||||
DEBUG(net, 0, "Failed to open connection to %s for redirecting DEBUG()", this->connection_string.c_str());
|
||||
}
|
||||
|
||||
_debug_socket = s;
|
||||
void OnConnect(SOCKET s) override
|
||||
{
|
||||
DEBUG(net, 3, "Redirecting DEBUG() to %s", this->connection_string.c_str());
|
||||
|
||||
DEBUG(net, 0, "DEBUG() is now redirected");
|
||||
extern SOCKET _debug_socket;
|
||||
_debug_socket = s;
|
||||
}
|
||||
};
|
||||
|
||||
void NetworkStartDebugLog(const std::string &connection_string)
|
||||
{
|
||||
new TCPNetworkDebugConnecter(connection_string);
|
||||
}
|
||||
|
||||
/** This tries to launch the network for a given OS */
|
||||
void NetworkStartUp()
|
||||
{
|
||||
DEBUG(net, 3, "[core] starting network...");
|
||||
DEBUG(net, 3, "Starting network");
|
||||
|
||||
/* Network is available */
|
||||
_network_available = NetworkCoreInitialize();
|
||||
@@ -1230,7 +1286,7 @@ void NetworkStartUp()
|
||||
_network_game_info = {};
|
||||
|
||||
NetworkInitialize();
|
||||
DEBUG(net, 3, "[core] network online, multiplayer available");
|
||||
DEBUG(net, 3, "Network online, multiplayer available");
|
||||
NetworkFindBroadcastIPs(&_broadcast_list);
|
||||
}
|
||||
|
||||
@@ -1240,7 +1296,7 @@ void NetworkShutDown()
|
||||
NetworkDisconnect(true);
|
||||
NetworkUDPClose();
|
||||
|
||||
DEBUG(net, 3, "[core] shutting down network");
|
||||
DEBUG(net, 3, "Shutting down network");
|
||||
|
||||
_network_available = false;
|
||||
|
||||
@@ -1252,7 +1308,7 @@ extern "C" {
|
||||
|
||||
void CDECL em_openttd_add_server(const char *connection_string)
|
||||
{
|
||||
NetworkAddServer(connection_string);
|
||||
NetworkAddServer(connection_string, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ ServerNetworkAdminSocketHandler::ServerNetworkAdminSocketHandler(SOCKET s) : Net
|
||||
ServerNetworkAdminSocketHandler::~ServerNetworkAdminSocketHandler()
|
||||
{
|
||||
_network_admins_connected--;
|
||||
DEBUG(net, 1, "[admin] '%s' (%s) has disconnected", this->admin_name, this->admin_version);
|
||||
DEBUG(net, 3, "[admin] '%s' (%s) has disconnected", this->admin_name, this->admin_version);
|
||||
if (_redirect_console_to_admin == this->index) _redirect_console_to_admin = INVALID_ADMIN_ID;
|
||||
|
||||
if (this->update_frequency[ADMIN_UPDATE_CONSOLE] & ADMIN_FREQUENCY_AUTOMATIC) {
|
||||
@@ -102,7 +102,7 @@ ServerNetworkAdminSocketHandler::~ServerNetworkAdminSocketHandler()
|
||||
{
|
||||
for (ServerNetworkAdminSocketHandler *as : ServerNetworkAdminSocketHandler::Iterate()) {
|
||||
if (as->status == ADMIN_STATUS_INACTIVE && std::chrono::steady_clock::now() > as->connect_time + ADMIN_AUTHORISATION_TIMEOUT) {
|
||||
DEBUG(net, 1, "[admin] Admin did not send its authorisation within %d seconds", (uint32)std::chrono::duration_cast<std::chrono::seconds>(ADMIN_AUTHORISATION_TIMEOUT).count());
|
||||
DEBUG(net, 2, "[admin] Admin did not send its authorisation within %d seconds", (uint32)std::chrono::duration_cast<std::chrono::seconds>(ADMIN_AUTHORISATION_TIMEOUT).count());
|
||||
as->CloseConnection(true);
|
||||
continue;
|
||||
}
|
||||
@@ -142,7 +142,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendError(NetworkErrorCode er
|
||||
StringID strid = GetNetworkErrorMsg(error);
|
||||
GetString(str, strid, lastof(str));
|
||||
|
||||
DEBUG(net, 1, "[admin] the admin '%s' (%s) made an error and has been disconnected. Reason: '%s'", this->admin_name, this->admin_version, str);
|
||||
DEBUG(net, 1, "[admin] The admin '%s' (%s) made an error and has been disconnected: '%s'", this->admin_name, this->admin_version, str);
|
||||
|
||||
return this->CloseConnection(true);
|
||||
}
|
||||
@@ -523,7 +523,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_RCON(Packet *p)
|
||||
|
||||
p->Recv_string(command, sizeof(command));
|
||||
|
||||
DEBUG(net, 2, "[admin] Rcon command from '%s' (%s): '%s'", this->admin_name, this->admin_version, command);
|
||||
DEBUG(net, 3, "[admin] Rcon command from '%s' (%s): %s", this->admin_name, this->admin_version, command);
|
||||
|
||||
_redirect_console_to_admin = this->index;
|
||||
IConsoleCmdExec(command);
|
||||
@@ -539,7 +539,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Pack
|
||||
|
||||
p->Recv_string(json, sizeof(json));
|
||||
|
||||
DEBUG(net, 2, "[admin] GameScript JSON from '%s' (%s): '%s'", this->admin_name, this->admin_version, json);
|
||||
DEBUG(net, 6, "[admin] GameScript JSON from '%s' (%s): %s", this->admin_name, this->admin_version, json);
|
||||
|
||||
Game::NewEvent(new ScriptEventAdminPort(json));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
@@ -551,7 +551,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_PING(Packet *p)
|
||||
|
||||
uint32 d1 = p->Recv_uint32();
|
||||
|
||||
DEBUG(net, 2, "[admin] Ping from '%s' (%s): '%d'", this->admin_name, this->admin_version, d1);
|
||||
DEBUG(net, 6, "[admin] Ping from '%s' (%s): %d", this->admin_name, this->admin_version, d1);
|
||||
|
||||
return this->SendPong(d1);
|
||||
}
|
||||
@@ -688,7 +688,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_JOIN(Packet *p)
|
||||
|
||||
this->status = ADMIN_STATUS_ACTIVE;
|
||||
|
||||
DEBUG(net, 1, "[admin] '%s' (%s) has connected", this->admin_name, this->admin_version);
|
||||
DEBUG(net, 3, "[admin] '%s' (%s) has connected", this->admin_name, this->admin_version);
|
||||
|
||||
return this->SendProtocol();
|
||||
}
|
||||
@@ -708,7 +708,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_UPDATE_FREQUENC
|
||||
|
||||
if (type >= ADMIN_UPDATE_END || (_admin_update_type_frequencies[type] & freq) != freq) {
|
||||
/* The server does not know of this UpdateType. */
|
||||
DEBUG(net, 3, "[admin] Not supported update frequency %d (%d) from '%s' (%s).", type, freq, this->admin_name, this->admin_version);
|
||||
DEBUG(net, 1, "[admin] Not supported update frequency %d (%d) from '%s' (%s)", type, freq, this->admin_name, this->admin_version);
|
||||
return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET);
|
||||
}
|
||||
|
||||
@@ -778,7 +778,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet *p)
|
||||
|
||||
default:
|
||||
/* An unsupported "poll" update type. */
|
||||
DEBUG(net, 3, "[admin] Not supported poll %d (%d) from '%s' (%s).", type, d1, this->admin_name, this->admin_version);
|
||||
DEBUG(net, 1, "[admin] Not supported poll %d (%d) from '%s' (%s).", type, d1, this->admin_name, this->admin_version);
|
||||
return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET);
|
||||
}
|
||||
|
||||
@@ -805,7 +805,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_CHAT(Packet *p)
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG(net, 3, "[admin] Invalid chat action %d from admin '%s' (%s).", action, this->admin_name, this->admin_version);
|
||||
DEBUG(net, 1, "[admin] Invalid chat action %d from admin '%s' (%s).", action, this->admin_name, this->admin_version);
|
||||
return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ static const uint NETWORK_CHAT_LINE_SPACING = 3;
|
||||
|
||||
/** Container for a message. */
|
||||
struct ChatMessage {
|
||||
char message[DRAW_STRING_BUFFER]; ///< The action message.
|
||||
std::string message; ///< The action message.
|
||||
TextColour colour; ///< The colour of the message.
|
||||
std::chrono::steady_clock::time_point remove_time; ///< The time to remove the message.
|
||||
};
|
||||
@@ -87,23 +87,14 @@ static inline bool HaveChatMessages(bool show_all)
|
||||
* @param duration The duration of the chat message in seconds
|
||||
* @param message message itself in printf() style
|
||||
*/
|
||||
void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const char *message, ...)
|
||||
void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const std::string &message)
|
||||
{
|
||||
char buf[DRAW_STRING_BUFFER];
|
||||
va_list va;
|
||||
|
||||
va_start(va, message);
|
||||
vseprintf(buf, lastof(buf), message, va);
|
||||
va_end(va);
|
||||
|
||||
Utf8TrimString(buf, DRAW_STRING_BUFFER);
|
||||
|
||||
if (_chatmsg_list.size() == MAX_CHAT_MESSAGES) {
|
||||
_chatmsg_list.pop_back();
|
||||
}
|
||||
|
||||
ChatMessage *cmsg = &_chatmsg_list.emplace_front();
|
||||
strecpy(cmsg->message, buf, lastof(cmsg->message));
|
||||
cmsg->message = message;
|
||||
cmsg->colour = (colour & TC_IS_PALETTE_COLOUR) ? colour : TC_WHITE;
|
||||
cmsg->remove_time = std::chrono::steady_clock::now() + std::chrono::seconds(duration);
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
if (this->sock == INVALID_SOCKET) return status;
|
||||
if (this->status == STATUS_CLOSING) return status;
|
||||
|
||||
DEBUG(net, 1, "Shutting down client connection %d", this->client_id);
|
||||
DEBUG(net, 3, "Shutting down client connection %d", this->client_id);
|
||||
|
||||
SetBlocking(this->sock);
|
||||
|
||||
@@ -350,7 +350,7 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
||||
|
||||
_sync_frame = 0;
|
||||
} else if (_sync_frame < _frame_counter) {
|
||||
DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter);
|
||||
DEBUG(net, 1, "Missed frame for sync-test: %d / %d", _sync_frame, _frame_counter);
|
||||
_sync_frame = 0;
|
||||
}
|
||||
}
|
||||
@@ -542,7 +542,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendCommand(const CommandPacke
|
||||
/** Send a chat-packet over the network */
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendChat(NetworkAction action, DestType type, int dest, const char *msg, NetworkTextMessageData data)
|
||||
{
|
||||
if (!my_client) return NETWORK_RECV_STATUS_CONN_LOST;
|
||||
if (!my_client) return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||
Packet *p = new Packet(PACKET_CLIENT_CHAT, SHRT_MAX);
|
||||
|
||||
p->Send_uint8 (action);
|
||||
@@ -799,7 +799,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
|
||||
p->Recv_string(name, sizeof(name));
|
||||
|
||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||
/* The server validates the name when receiving it from clients, so when it is wrong
|
||||
* here something went really wrong. In the best case the packet got malformed on its
|
||||
* way too us, in the worst case the server is broken or compromised. */
|
||||
@@ -1131,13 +1131,13 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p
|
||||
/* Receive the token. */
|
||||
if (p->CanReadFromPacket(sizeof(uint8))) this->token = p->Recv_uint8();
|
||||
|
||||
DEBUG(net, 5, "Received FRAME %d", _frame_counter_server);
|
||||
DEBUG(net, 7, "Received FRAME %d", _frame_counter_server);
|
||||
|
||||
/* 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;
|
||||
DEBUG(net, 4, "Sent ACK at %d", _frame_counter);
|
||||
DEBUG(net, 7, "Sent ACK at %d", _frame_counter);
|
||||
SendAck();
|
||||
}
|
||||
|
||||
@@ -1272,7 +1272,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p)
|
||||
NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, nullptr, STR_NETWORK_MESSAGE_CLIENT_LEAVING);
|
||||
delete ci;
|
||||
} else {
|
||||
DEBUG(net, 0, "Unknown client (%d) is leaving the game", client_id);
|
||||
DEBUG(net, 1, "Unknown client (%d) is leaving the game", client_id);
|
||||
}
|
||||
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
@@ -1352,7 +1352,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MOVE(Packet *p)
|
||||
|
||||
if (client_id == 0) {
|
||||
/* definitely an invalid client id, debug message and do nothing. */
|
||||
DEBUG(net, 0, "[move] received invalid client index = 0");
|
||||
DEBUG(net, 1, "Received invalid client index = 0");
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
|
||||
|
||||
@@ -367,7 +367,7 @@ void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
|
||||
}
|
||||
|
||||
if (callback == lengthof(_callback_table)) {
|
||||
DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", cp->callback);
|
||||
DEBUG(net, 0, "Unknown callback for command; no callback sent (command: %d)", cp->cmd);
|
||||
callback = 0; // _callback_table[0] == nullptr
|
||||
}
|
||||
p->Send_uint8 (callback);
|
||||
|
||||
@@ -808,7 +808,9 @@ void ClientNetworkContentSocketHandler::Connect()
|
||||
void ClientNetworkContentSocketHandler::Close()
|
||||
{
|
||||
if (this->sock == INVALID_SOCKET) return;
|
||||
NetworkContentSocketHandler::Close();
|
||||
|
||||
this->CloseConnection();
|
||||
this->CloseSocket();
|
||||
|
||||
this->OnDisconnect();
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
|
||||
void Connect();
|
||||
void SendReceive();
|
||||
void Close() override;
|
||||
void Close();
|
||||
|
||||
void RequestContentList(ContentType type);
|
||||
void RequestContentList(uint count, const ContentID *content_ids);
|
||||
|
||||
@@ -86,7 +86,7 @@ uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const char *reason);
|
||||
uint NetworkServerKickOrBanIP(const char *ip, bool ban, const char *reason);
|
||||
|
||||
void NetworkInitChatMessage();
|
||||
void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const char *message, ...) WARN_FORMAT(3, 4);
|
||||
void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const std::string &message);
|
||||
void NetworkUndrawChatMessage();
|
||||
void NetworkChatMessageLoop();
|
||||
|
||||
|
||||
@@ -112,7 +112,6 @@ void NetworkGameListRemoveItem(NetworkGameList *remove)
|
||||
ClearGRFConfigList(&remove->info.grfconfig);
|
||||
delete remove;
|
||||
|
||||
DEBUG(net, 4, "[gamelist] removed server from list");
|
||||
NetworkRebuildHostList();
|
||||
UpdateNetworkGameWindow();
|
||||
return;
|
||||
|
||||
@@ -491,7 +491,7 @@ public:
|
||||
EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
|
||||
#endif
|
||||
|
||||
this->last_joined = NetworkAddServer(_settings_client.network.last_joined);
|
||||
this->last_joined = NetworkAddServer(_settings_client.network.last_joined, false);
|
||||
this->server = this->last_joined;
|
||||
|
||||
this->requery_timer.SetInterval(MILLISECONDS_PER_TICK);
|
||||
@@ -767,7 +767,7 @@ public:
|
||||
break;
|
||||
|
||||
case WID_NG_REFRESH: // Refresh
|
||||
if (this->server != nullptr) NetworkTCPQueryServer(this->server->connection_string);
|
||||
if (this->server != nullptr) NetworkQueryServer(this->server->connection_string);
|
||||
break;
|
||||
|
||||
case WID_NG_NEWGRF: // NewGRF Settings
|
||||
@@ -845,6 +845,7 @@ public:
|
||||
if (!StrEmpty(str)) {
|
||||
strecpy(_settings_client.network.connect_to_ip, str, lastof(_settings_client.network.connect_to_ip));
|
||||
NetworkAddServer(str);
|
||||
NetworkRebuildHostList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1502,7 +1503,7 @@ struct NetworkLobbyWindow : public Window {
|
||||
/* Clear the information so removed companies don't remain */
|
||||
for (auto &company : this->company_info) company = {};
|
||||
|
||||
NetworkTCPQueryServer(this->server->connection_string, true);
|
||||
NetworkQueryLobbyServer(this->server->connection_string);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1572,7 +1573,7 @@ static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
|
||||
|
||||
strecpy(_settings_client.network.last_joined, ngl->connection_string.c_str(), lastof(_settings_client.network.last_joined));
|
||||
|
||||
NetworkTCPQueryServer(ngl->connection_string, true);
|
||||
NetworkQueryLobbyServer(ngl->connection_string);
|
||||
|
||||
new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
|
||||
}
|
||||
|
||||
@@ -94,10 +94,11 @@ extern uint8 _network_reconnect;
|
||||
|
||||
extern CompanyMask _network_company_passworded;
|
||||
|
||||
void NetworkTCPQueryServer(const std::string &connection_string, bool request_company_info = false);
|
||||
void NetworkQueryServer(const std::string &connection_string);
|
||||
void NetworkQueryLobbyServer(const std::string &connection_string);
|
||||
|
||||
void GetBindAddresses(NetworkAddressList *addresses, uint16 port);
|
||||
struct NetworkGameList *NetworkAddServer(const std::string &connection_string);
|
||||
struct NetworkGameList *NetworkAddServer(const std::string &connection_string, bool manually = true);
|
||||
void NetworkRebuildHostList();
|
||||
void UpdateNetworkGameWindow();
|
||||
|
||||
@@ -127,5 +128,6 @@ bool NetworkFindName(char *new_name, const char *last);
|
||||
const char *GenerateCompanyPasswordHash(const char *password, const char *password_server_id, uint32 password_game_seed);
|
||||
|
||||
NetworkAddress ParseConnectionString(const std::string &connection_string, uint16 default_port);
|
||||
std::string NormalizeConnectionString(const std::string &connection_string, uint16 default_port);
|
||||
|
||||
#endif /* NETWORK_INTERNAL_H */
|
||||
|
||||
@@ -253,7 +253,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
*/
|
||||
if (this->sock == INVALID_SOCKET) return status;
|
||||
|
||||
if (status != NETWORK_RECV_STATUS_CONN_LOST && status != NETWORK_RECV_STATUS_SERVER_ERROR && !this->HasClientQuit() && this->status >= STATUS_AUTHORIZED) {
|
||||
if (status != NETWORK_RECV_STATUS_CLIENT_QUIT && status != NETWORK_RECV_STATUS_SERVER_ERROR && !this->HasClientQuit() && this->status >= STATUS_AUTHORIZED) {
|
||||
/* We did not receive a leave message from this client... */
|
||||
char client_name[NETWORK_CLIENT_NAME_LENGTH];
|
||||
|
||||
@@ -280,7 +280,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
}
|
||||
|
||||
NetworkAdminClientError(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
|
||||
DEBUG(net, 1, "Closed client connection %d", this->client_id);
|
||||
DEBUG(net, 3, "Closed client connection %d", this->client_id);
|
||||
|
||||
/* We just lost one client :( */
|
||||
if (this->status >= STATUS_AUTHORIZED) _network_game_info.clients_on--;
|
||||
@@ -321,7 +321,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
if (cs->status == STATUS_CLOSE_PENDING) {
|
||||
SendPacketsState send_state = cs->SendPackets(true);
|
||||
if (send_state == SPS_CLOSED) {
|
||||
cs->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
||||
cs->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
|
||||
} else if (send_state != SPS_PARTLY_SENT && send_state != SPS_NONE_SENT) {
|
||||
ShutdownSocket(cs->sock, true, false, 2);
|
||||
}
|
||||
@@ -462,7 +462,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode err
|
||||
|
||||
this->GetClientName(client_name, lastof(client_name));
|
||||
|
||||
DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str);
|
||||
DEBUG(net, 1, "'%s' made an error and has been disconnected: %s", client_name, str);
|
||||
|
||||
if (error == NETWORK_ERROR_KICKED && reason != nullptr) {
|
||||
NetworkTextMessage(NETWORK_ACTION_KICKED, CC_DEFAULT, false, client_name, reason, strid);
|
||||
@@ -483,7 +483,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode err
|
||||
|
||||
NetworkAdminClientError(this->client_id, error);
|
||||
} else {
|
||||
DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", this->client_id, str);
|
||||
DEBUG(net, 1, "Client %d made an error and has been disconnected: %s", this->client_id, str);
|
||||
}
|
||||
|
||||
/* The client made a mistake, so drop his connection now! */
|
||||
@@ -947,7 +947,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p)
|
||||
p->Recv_string(name, sizeof(name));
|
||||
playas = (Owner)p->Recv_uint8();
|
||||
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||
|
||||
/* join another company does not affect these values */
|
||||
switch (playas) {
|
||||
@@ -1160,7 +1160,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet
|
||||
CommandPacket cp;
|
||||
const char *err = this->ReceiveCommand(p, &cp);
|
||||
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||
|
||||
NetworkClientInfo *ci = this->GetInfo();
|
||||
|
||||
@@ -1225,7 +1225,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p
|
||||
if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
|
||||
if (_debug_net_level >= 2) GetString(str, GetNetworkErrorMsg(errorno), lastof(str));
|
||||
DEBUG(net, 2, "non-joined client %d reported an error and is closing its connection (%s) (%d, %d, %d)", this->client_id, str, rx_status, status, last_pkt_type);
|
||||
return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
||||
return this->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
|
||||
}
|
||||
|
||||
this->GetClientName(client_name, lastof(client_name));
|
||||
@@ -1233,7 +1233,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p
|
||||
StringID strid = GetNetworkErrorMsg(errorno);
|
||||
GetString(str, strid, lastof(str));
|
||||
|
||||
DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s) (%d, %d, %d)", client_name, str, rx_status, status, last_pkt_type);
|
||||
DEBUG(net, 1, "'%s' reported an error and is closing its connection (%s) (%d, %d, %d)", client_name, str, rx_status, status, last_pkt_type);
|
||||
|
||||
NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, nullptr, strid);
|
||||
|
||||
@@ -1262,7 +1262,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
}
|
||||
return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
||||
return this->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_DESYNC_LOG(Packet *p)
|
||||
@@ -1296,7 +1296,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p)
|
||||
|
||||
/* The client was never joined.. thank the client for the packet, but ignore it */
|
||||
if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
|
||||
return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
||||
return this->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
|
||||
}
|
||||
|
||||
this->GetClientName(client_name, lastof(client_name));
|
||||
@@ -1311,7 +1311,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p)
|
||||
|
||||
NetworkAdminClientQuit(this->client_id);
|
||||
|
||||
return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
||||
return this->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ACK(Packet *p)
|
||||
@@ -1464,7 +1464,7 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype);
|
||||
DEBUG(net, 1, "Received unknown chat destination type %d; doing broadcast instead", desttype);
|
||||
FALLTHROUGH;
|
||||
|
||||
case DESTTYPE_BROADCAST:
|
||||
@@ -1547,7 +1547,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet
|
||||
p->Recv_string(client_name, sizeof(client_name));
|
||||
ci = this->GetInfo();
|
||||
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||
|
||||
if (ci != nullptr) {
|
||||
if (!NetworkIsValidClientName(client_name)) {
|
||||
@@ -1588,7 +1588,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p)
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", this->client_id, command);
|
||||
DEBUG(net, 3, "[rcon] Client-id %d executed: %s", this->client_id, command);
|
||||
|
||||
_redirect_console_to_client = this->client_id;
|
||||
IConsoleCmdExec(command);
|
||||
@@ -1613,7 +1613,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet *p)
|
||||
|
||||
/* Incorrect password sent, return! */
|
||||
if (strcmp(password, _network_company_states[company_id].password) != 0) {
|
||||
DEBUG(net, 2, "[move] wrong password from client-id #%d for company #%d", this->client_id, company_id + 1);
|
||||
DEBUG(net, 2, "Wrong password from client-id #%d for company #%d", this->client_id, company_id + 1);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
}
|
||||
@@ -1760,7 +1760,7 @@ void NetworkUpdateClientInfo(ClientID client_id)
|
||||
static void NetworkCheckRestartMap()
|
||||
{
|
||||
if (_settings_client.network.restart_game_year != 0 && _cur_year >= _settings_client.network.restart_game_year) {
|
||||
DEBUG(net, 0, "Auto-restarting map. Year %d reached", _cur_year);
|
||||
DEBUG(net, 3, "Auto-restarting map: year %d reached", _cur_year);
|
||||
|
||||
_settings_newgame.game_creation.generation_seed = GENERATE_NEW_SEED;
|
||||
switch(_file_to_saveload.abstract_ftype) {
|
||||
|
||||
@@ -77,7 +77,7 @@ struct UDPSocket {
|
||||
std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
|
||||
if (!lock.try_lock()) {
|
||||
if (++receive_iterations_locked % 32 == 0) {
|
||||
DEBUG(net, 0, "[udp] %s background UDP loop processing appears to be blocked. Your OS may be low on UDP send buffers.", name.c_str());
|
||||
DEBUG(net, 0, "%s background UDP loop processing appears to be blocked. Your OS may be low on UDP send buffers.", name.c_str());
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -152,7 +152,7 @@ public:
|
||||
void MasterNetworkUDPSocketHandler::Receive_MASTER_ACK_REGISTER(Packet *p, NetworkAddress *client_addr)
|
||||
{
|
||||
_network_advertise_retries = 0;
|
||||
DEBUG(net, 2, "[udp] advertising on master server successful (%s)", NetworkAddress::AddressFamilyAsString(client_addr->GetAddress()->ss_family));
|
||||
DEBUG(net, 3, "Advertising on master server successful (%s)", NetworkAddress::AddressFamilyAsString(client_addr->GetAddress()->ss_family));
|
||||
|
||||
/* We are advertised, but we don't want to! */
|
||||
if (!_settings_client.network.server_advertise) NetworkUDPRemoveAdvertise(false);
|
||||
@@ -161,7 +161,7 @@ void MasterNetworkUDPSocketHandler::Receive_MASTER_ACK_REGISTER(Packet *p, Netwo
|
||||
void MasterNetworkUDPSocketHandler::Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr)
|
||||
{
|
||||
_session_key = p->Recv_uint64();
|
||||
DEBUG(net, 2, "[udp] received new session key from master server (%s)", NetworkAddress::AddressFamilyAsString(client_addr->GetAddress()->ss_family));
|
||||
DEBUG(net, 6, "Received new session key from master server (%s)", NetworkAddress::AddressFamilyAsString(client_addr->GetAddress()->ss_family));
|
||||
}
|
||||
|
||||
///*** Communication with clients (we are server) ***/
|
||||
@@ -200,7 +200,7 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, Networ
|
||||
/* Let the client know that we are here */
|
||||
this->SendPacket(&packet, client_addr);
|
||||
|
||||
DEBUG(net, 2, "[udp] queried from %s", client_addr->GetHostname());
|
||||
DEBUG(net, 7, "Queried from %s", client_addr->GetHostname());
|
||||
}
|
||||
|
||||
void ServerNetworkUDPSocketHandler::Reply_CLIENT_FIND_SERVER_extended(Packet *p, NetworkAddress *client_addr, const NetworkServerGameInfo *ngi)
|
||||
@@ -293,6 +293,8 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ
|
||||
};
|
||||
std::vector<GRFInfo> in_reply;
|
||||
|
||||
DEBUG(net, 7, "NewGRF data request from %s", client_addr->GetAddressAsString().c_str());
|
||||
|
||||
size_t packet_len = 0;
|
||||
|
||||
num_grfs = p->Recv_uint8 ();
|
||||
@@ -389,7 +391,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE_Common(Packet *p, Ne
|
||||
/* Just a fail-safe.. should never happen */
|
||||
if (_network_udp_server) return;
|
||||
|
||||
DEBUG(net, 4, "[udp]%s server response from %s", extended ? " extended" : "", NetworkAddressDumper().GetAddressAsString(client_addr));
|
||||
DEBUG(net, 3, "%s server response from %s", extended ? " extended" : "", NetworkAddressDumper().GetAddressAsString(client_addr));
|
||||
|
||||
/* Find next item */
|
||||
item = NetworkGameListAddItem(client_addr->GetAddressAsString(false));
|
||||
@@ -498,7 +500,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAdd
|
||||
uint i;
|
||||
|
||||
num_grfs = p->Recv_uint8 ();
|
||||
DEBUG(net, 6, "[udp] newgrf data reply (%u) from %s", num_grfs, NetworkAddressDumper().GetAddressAsString(client_addr));
|
||||
DEBUG(net, 7, "NewGRF data reply (%u) from %s", num_grfs, NetworkAddressDumper().GetAddressAsString(client_addr));
|
||||
|
||||
if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
|
||||
|
||||
@@ -529,7 +531,7 @@ static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket)
|
||||
for (NetworkAddress &addr : _broadcast_list) {
|
||||
Packet p = PrepareUdpClientFindServerPacket();
|
||||
|
||||
DEBUG(net, 4, "[udp] broadcasting to %s", addr.GetHostname());
|
||||
DEBUG(net, 5, "Broadcasting to %s", addr.GetHostname());
|
||||
|
||||
socket->SendPacket(&p, &addr, true, true);
|
||||
}
|
||||
@@ -549,7 +551,7 @@ void NetworkUDPQueryMasterServer()
|
||||
std::lock_guard<std::mutex> lock(_udp_client.mutex);
|
||||
_udp_client.socket->SendPacket(&p, &out_addr, true);
|
||||
|
||||
DEBUG(net, 2, "[udp] master server queried at %s", NetworkAddressDumper().GetAddressAsString(&out_addr));
|
||||
DEBUG(net, 6, "Master server queried at %s", NetworkAddressDumper().GetAddressAsString(&out_addr));
|
||||
}
|
||||
|
||||
/** Find all servers */
|
||||
@@ -558,7 +560,7 @@ void NetworkUDPSearchGame()
|
||||
/* We are still searching.. */
|
||||
if (_network_udp_broadcast > 0) return;
|
||||
|
||||
DEBUG(net, 0, "[udp] searching server");
|
||||
DEBUG(net, 3, "Searching server");
|
||||
|
||||
NetworkUDPBroadCast(_udp_client.socket);
|
||||
_network_udp_broadcast = 300; // Stay searching for 300 ticks
|
||||
@@ -569,7 +571,7 @@ void NetworkUDPSearchGame()
|
||||
*/
|
||||
static void NetworkUDPRemoveAdvertiseThread()
|
||||
{
|
||||
DEBUG(net, 1, "[udp] removing advertise from master server");
|
||||
DEBUG(net, 3, "Removing advertise from master server");
|
||||
|
||||
/* Find somewhere to send */
|
||||
NetworkAddress out_addr(NETWORK_MASTER_SERVER_HOST, NETWORK_MASTER_SERVER_PORT);
|
||||
@@ -606,22 +608,22 @@ static void NetworkUDPAdvertiseThread()
|
||||
/* Find somewhere to send */
|
||||
NetworkAddress out_addr(NETWORK_MASTER_SERVER_HOST, NETWORK_MASTER_SERVER_PORT);
|
||||
|
||||
DEBUG(net, 1, "[udp] advertising to master server");
|
||||
DEBUG(net, 3, "Advertising to master server");
|
||||
|
||||
/* Add a bit more messaging when we cannot get a session key */
|
||||
static byte session_key_retries = 0;
|
||||
if (_session_key == 0 && session_key_retries++ == 2) {
|
||||
DEBUG(net, 0, "[udp] advertising to the master server is failing");
|
||||
DEBUG(net, 0, "[udp] we are not receiving the session key from the server");
|
||||
DEBUG(net, 0, "[udp] please allow udp packets from %s to you to be delivered", NetworkAddressDumper().GetAddressAsString(&out_addr, false));
|
||||
DEBUG(net, 0, "[udp] please allow udp packets from you to %s to be delivered", NetworkAddressDumper().GetAddressAsString(&out_addr, false));
|
||||
DEBUG(net, 0, "Advertising to the master server is failing");
|
||||
DEBUG(net, 0, " we are not receiving the session key from the server");
|
||||
DEBUG(net, 0, " please allow udp packets from %s to you to be delivered", NetworkAddressDumper().GetAddressAsString(&out_addr, false));
|
||||
DEBUG(net, 0, " please allow udp packets from you to %s to be delivered", NetworkAddressDumper().GetAddressAsString(&out_addr, false));
|
||||
}
|
||||
if (_session_key != 0 && _network_advertise_retries == 0) {
|
||||
DEBUG(net, 0, "[udp] advertising to the master server is failing");
|
||||
DEBUG(net, 0, "[udp] we are not receiving the acknowledgement from the server");
|
||||
DEBUG(net, 0, "[udp] this usually means that the master server cannot reach us");
|
||||
DEBUG(net, 0, "[udp] please allow udp and tcp packets to port %u to be delivered", _settings_client.network.server_port);
|
||||
DEBUG(net, 0, "[udp] please allow udp and tcp packets from port %u to be delivered", _settings_client.network.server_port);
|
||||
DEBUG(net, 0, "Advertising to the master server is failing");
|
||||
DEBUG(net, 0, " we are not receiving the acknowledgement from the server");
|
||||
DEBUG(net, 0, " this usually means that the master server cannot reach us");
|
||||
DEBUG(net, 0, " please allow udp and tcp packets to port %u to be delivered", _settings_client.network.server_port);
|
||||
DEBUG(net, 0, " please allow udp and tcp packets from port %u to be delivered", _settings_client.network.server_port);
|
||||
}
|
||||
|
||||
/* Send the packet */
|
||||
@@ -677,7 +679,7 @@ void NetworkUDPInitialize()
|
||||
/* If not closed, then do it. */
|
||||
if (_udp_server.socket != nullptr) NetworkUDPClose();
|
||||
|
||||
DEBUG(net, 1, "[udp] initializing listeners");
|
||||
DEBUG(net, 3, "Initializing UDP listeners");
|
||||
assert(_udp_client.socket == nullptr && _udp_server.socket == nullptr && _udp_master.socket == nullptr);
|
||||
|
||||
// std::scoped_lock lock(_udp_client.mutex, _udp_server.mutex, _udp_master.mutex);
|
||||
@@ -719,7 +721,7 @@ void NetworkUDPClose()
|
||||
|
||||
_network_udp_server = false;
|
||||
_network_udp_broadcast = 0;
|
||||
DEBUG(net, 1, "[udp] closed listeners");
|
||||
DEBUG(net, 5, "Closed UDP listeners");
|
||||
}
|
||||
|
||||
/** Receive the UDP packets. */
|
||||
|
||||
Reference in New Issue
Block a user