mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-17 03:53:07 +01:00
Merge pull request #2141 from zsilencer/network
ipv6 support, non-blocking address resolve and connect
This commit is contained in:
@@ -259,7 +259,7 @@ void game_update()
|
||||
numUpdates = clamp(1, numUpdates, 4);
|
||||
}
|
||||
|
||||
if (network_get_mode() == NETWORK_MODE_CLIENT) {
|
||||
if (network_get_mode() == NETWORK_MODE_CLIENT && network_get_status() == NETWORK_STATUS_CONNECTED) {
|
||||
if (network_get_server_tick() - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) >= 10) {
|
||||
// make sure client doesn't fall behind the server too much
|
||||
numUpdates += 10;
|
||||
@@ -335,7 +335,7 @@ void game_update()
|
||||
void game_logic_update()
|
||||
{
|
||||
network_update();
|
||||
if (network_get_mode() == NETWORK_MODE_CLIENT) {
|
||||
if (network_get_mode() == NETWORK_MODE_CLIENT && network_get_status() == NETWORK_STATUS_CONNECTED) {
|
||||
if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) >= network_get_server_tick()) {
|
||||
// dont run past the server
|
||||
return;
|
||||
|
||||
@@ -59,6 +59,9 @@ void chat_update()
|
||||
|
||||
void chat_draw()
|
||||
{
|
||||
if (network_get_mode() == NETWORK_MODE_NONE) {
|
||||
return;
|
||||
}
|
||||
rct_drawpixelinfo *dpi = (rct_drawpixelinfo*)RCT2_ADDRESS_SCREEN_DPI;
|
||||
_chatLeft = 10;
|
||||
_chatTop = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 40 - ((CHAT_HISTORY_SIZE + 1) * 10);
|
||||
@@ -108,7 +111,9 @@ void chat_input(int c)
|
||||
{
|
||||
switch (c) {
|
||||
case SDL_SCANCODE_RETURN:
|
||||
network_send_chat(_chatCurrentLine);
|
||||
if (strlen(_chatCurrentLine) > 0) {
|
||||
network_send_chat(_chatCurrentLine);
|
||||
}
|
||||
chat_clear_input();
|
||||
chat_close();
|
||||
break;
|
||||
|
||||
@@ -33,6 +33,7 @@ extern "C" {
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <string>
|
||||
extern "C" {
|
||||
#include "../config.h"
|
||||
#include "../game.h"
|
||||
@@ -41,6 +42,7 @@ extern "C" {
|
||||
#include "../localisation/date.h"
|
||||
#include "../localisation/localisation.h"
|
||||
#include "../scenario.h"
|
||||
#include "../windows/error.h"
|
||||
}
|
||||
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
@@ -155,6 +157,14 @@ NetworkConnection::NetworkConnection()
|
||||
{
|
||||
authstatus = NETWORK_AUTH_NONE;
|
||||
player = 0;
|
||||
socket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
NetworkConnection::~NetworkConnection()
|
||||
{
|
||||
if (socket != INVALID_SOCKET) {
|
||||
closesocket(socket);
|
||||
}
|
||||
}
|
||||
|
||||
int NetworkConnection::ReadPacket()
|
||||
@@ -253,10 +263,78 @@ bool NetworkConnection::SetNonBlocking(SOCKET socket, bool on)
|
||||
#endif
|
||||
}
|
||||
|
||||
NetworkAddress::NetworkAddress()
|
||||
{
|
||||
ss = std::make_shared<sockaddr_storage>();
|
||||
ss_len = std::make_shared<int>();
|
||||
status = std::make_shared<int>();
|
||||
*status = RESOLVE_NONE;
|
||||
}
|
||||
|
||||
void NetworkAddress::Resolve(const char* host, unsigned short port, bool nonblocking)
|
||||
{
|
||||
// A non-blocking hostname resolver
|
||||
*status = RESOLVE_INPROGRESS;
|
||||
mutex = SDL_CreateMutex();
|
||||
cond = SDL_CreateCond();
|
||||
NetworkAddress::host = host;
|
||||
NetworkAddress::port = port;
|
||||
SDL_LockMutex(mutex);
|
||||
SDL_Thread* thread = SDL_CreateThread(ResolveFunc, 0, this);
|
||||
// The mutex/cond is to make sure ResolveFunc doesn't ever get a dangling pointer
|
||||
SDL_CondWait(cond, mutex);
|
||||
SDL_UnlockMutex(mutex);
|
||||
SDL_DestroyCond(cond);
|
||||
SDL_DestroyMutex(mutex);
|
||||
if (!nonblocking) {
|
||||
int status;
|
||||
SDL_WaitThread(thread, &status);
|
||||
}
|
||||
}
|
||||
|
||||
int NetworkAddress::GetResolveStatus(void)
|
||||
{
|
||||
return *status;
|
||||
}
|
||||
|
||||
int NetworkAddress::ResolveFunc(void* pointer)
|
||||
{
|
||||
// Copy data for thread safety
|
||||
NetworkAddress * networkaddress = (NetworkAddress*)pointer;
|
||||
SDL_LockMutex(networkaddress->mutex);
|
||||
std::string host;
|
||||
if (networkaddress->host) host = networkaddress->host;
|
||||
std::string port = std::to_string(networkaddress->port);
|
||||
std::shared_ptr<sockaddr_storage> ss = networkaddress->ss;
|
||||
std::shared_ptr<int> ss_len = networkaddress->ss_len;
|
||||
std::shared_ptr<int> status = networkaddress->status;
|
||||
SDL_CondSignal(networkaddress->cond);
|
||||
SDL_UnlockMutex(networkaddress->mutex);
|
||||
|
||||
// Perform the resolve
|
||||
addrinfo hints;
|
||||
addrinfo* res;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
if (host.length() == 0) {
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
}
|
||||
getaddrinfo(host.length() == 0 ? NULL : host.c_str(), port.c_str(), &hints, &res);
|
||||
if (res) {
|
||||
memcpy(&(*ss), res->ai_addr, res->ai_addrlen);
|
||||
*ss_len = res->ai_addrlen;
|
||||
*status = RESOLVE_OK;
|
||||
} else {
|
||||
*status = RESOLVE_FAILED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Network::Network()
|
||||
{
|
||||
wsa_initialized = false;
|
||||
mode = NETWORK_MODE_NONE;
|
||||
status = NETWORK_STATUS_NONE;
|
||||
last_tick_sent_time = 0;
|
||||
last_ping_sent_time = 0;
|
||||
strcpy(password, "");
|
||||
@@ -300,16 +378,15 @@ bool Network::Init()
|
||||
void Network::Close()
|
||||
{
|
||||
if (mode == NETWORK_MODE_CLIENT) {
|
||||
closesocket(server_socket);
|
||||
closesocket(server_connection.socket);
|
||||
} else
|
||||
if (mode == NETWORK_MODE_SERVER) {
|
||||
closesocket(listening_socket);
|
||||
for(auto it = client_connection_list.begin(); it != client_connection_list.end(); it++) {
|
||||
closesocket((*it)->socket);
|
||||
}
|
||||
}
|
||||
|
||||
mode = NETWORK_MODE_NONE;
|
||||
status = NETWORK_STATUS_NONE;
|
||||
server_connection.authstatus = NETWORK_AUTH_NONE;
|
||||
|
||||
client_connection_list.clear();
|
||||
game_command_queue.clear();
|
||||
@@ -331,69 +408,39 @@ bool Network::BeginClient(const char* host, unsigned short port)
|
||||
if (!Init())
|
||||
return false;
|
||||
|
||||
server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (server_socket == INVALID_SOCKET) {
|
||||
log_error("Unable to create socket.");
|
||||
return false;
|
||||
}
|
||||
server_address.Resolve(host, port);
|
||||
status = NETWORK_STATUS_RESOLVING;
|
||||
|
||||
sockaddr_in server_address;
|
||||
#ifdef USE_INET_PTON
|
||||
char address[64];
|
||||
if (!network_get_address(address, sizeof(address), host)) {
|
||||
log_error("Unable to resolve hostname.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, address, &server_address.sin_addr) != 1) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
server_address.sin_addr.S_un.S_addr = inet_addr(network_getAddress((char *)host));
|
||||
#endif // USE_INET_PTON
|
||||
server_address.sin_family = AF_INET;
|
||||
server_address.sin_port = htons(port);
|
||||
|
||||
if (connect(server_socket, (sockaddr*)&server_address, sizeof(server_address)) != 0) {
|
||||
log_error("Unable to connect to host.");
|
||||
return false;
|
||||
} else {
|
||||
printf("Connected to server!\n");
|
||||
}
|
||||
|
||||
server_connection.socket = server_socket;
|
||||
server_connection.SetTCPNoDelay(true);
|
||||
if (!server_connection.SetNonBlocking(true)) {
|
||||
closesocket(server_socket);
|
||||
log_error("Failed to set non-blocking mode.");
|
||||
return false;
|
||||
}
|
||||
window_network_status_open("Resolving...");
|
||||
|
||||
mode = NETWORK_MODE_CLIENT;
|
||||
|
||||
Client_Send_AUTH(OPENRCT2_VERSION, gConfigNetwork.player_name, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Network::BeginServer(unsigned short port)
|
||||
bool Network::BeginServer(unsigned short port, const char* address)
|
||||
{
|
||||
Close();
|
||||
if (!Init())
|
||||
return false;
|
||||
|
||||
NetworkAddress networkaddress;
|
||||
networkaddress.Resolve(address, port, false);
|
||||
|
||||
log_verbose("Begin listening for clients");
|
||||
listening_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
listening_socket = socket(networkaddress.ss->ss_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (listening_socket == INVALID_SOCKET) {
|
||||
log_error("Unable to create socket.");
|
||||
return false;
|
||||
}
|
||||
|
||||
sockaddr_in local_address;
|
||||
local_address.sin_family = AF_INET;
|
||||
local_address.sin_addr.s_addr = INADDR_ANY;
|
||||
local_address.sin_port = htons(port);
|
||||
// Turn off IPV6_V6ONLY so we can accept both v4 and v6 connections
|
||||
int value = 0;
|
||||
if (setsockopt(listening_socket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&value, sizeof(value)) != 0) {
|
||||
log_error("IPV6_V6ONLY failed. %d", LAST_SOCKET_ERROR());
|
||||
}
|
||||
|
||||
if (bind(listening_socket, (sockaddr*)&local_address, sizeof(local_address)) != 0) {
|
||||
if (bind(listening_socket, (sockaddr*)&(*networkaddress.ss), (*networkaddress.ss_len)) != 0) {
|
||||
closesocket(listening_socket);
|
||||
log_error("Unable to bind to socket.");
|
||||
return false;
|
||||
@@ -426,6 +473,11 @@ int Network::GetMode()
|
||||
return mode;
|
||||
}
|
||||
|
||||
int Network::GetStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
int Network::GetAuthStatus()
|
||||
{
|
||||
if (GetMode() == NETWORK_MODE_CLIENT) {
|
||||
@@ -470,11 +522,11 @@ void Network::UpdateServer()
|
||||
it++;
|
||||
}
|
||||
}
|
||||
if (SDL_GetTicks() - last_tick_sent_time >= 25) {
|
||||
if (SDL_TICKS_PASSED(SDL_GetTicks(), last_tick_sent_time + 25)) {
|
||||
last_tick_sent_time = SDL_GetTicks();
|
||||
Server_Send_TICK();
|
||||
}
|
||||
if (SDL_GetTicks() - last_ping_sent_time >= 3000) {
|
||||
if (SDL_TICKS_PASSED(SDL_GetTicks(), last_ping_sent_time + 3000)) {
|
||||
last_ping_sent_time = SDL_GetTicks();
|
||||
Server_Send_PING();
|
||||
Server_Send_PINGLIST();
|
||||
@@ -497,18 +549,91 @@ void Network::UpdateServer()
|
||||
|
||||
void Network::UpdateClient()
|
||||
{
|
||||
if (!ProcessConnection(server_connection)) {
|
||||
Close();
|
||||
}
|
||||
ProcessGameCommandQueue();
|
||||
bool connectfailed = false;
|
||||
switch(status){
|
||||
case NETWORK_STATUS_RESOLVING:{
|
||||
if(server_address.GetResolveStatus() == NetworkAddress::RESOLVE_OK){
|
||||
server_connection.socket = socket(server_address.ss->ss_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (server_connection.socket == INVALID_SOCKET) {
|
||||
log_error("Unable to create socket.");
|
||||
connectfailed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check synchronisation
|
||||
if (!_desynchronised && !CheckSRAND(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32), RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32))) {
|
||||
_desynchronised = true;
|
||||
window_network_status_open("Network desync detected");
|
||||
if (!gConfigNetwork.stay_connected) {
|
||||
server_connection.SetTCPNoDelay(true);
|
||||
if (!server_connection.SetNonBlocking(true)) {
|
||||
log_error("Failed to set non-blocking mode.");
|
||||
connectfailed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (connect(server_connection.socket, (sockaddr *)&(*server_address.ss), (*server_address.ss_len)) == SOCKET_ERROR && (LAST_SOCKET_ERROR() == EINPROGRESS || LAST_SOCKET_ERROR() == EWOULDBLOCK)){
|
||||
window_network_status_open("Connecting...");
|
||||
server_connect_time = SDL_GetTicks();
|
||||
status = NETWORK_STATUS_CONNECTING;
|
||||
} else {
|
||||
log_error("connect() failed %d", LAST_SOCKET_ERROR());
|
||||
connectfailed = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
log_error("Could not resolve address.");
|
||||
connectfailed = true;
|
||||
}
|
||||
}break;
|
||||
case NETWORK_STATUS_CONNECTING:{
|
||||
int error = 0;
|
||||
socklen_t len = sizeof(error);
|
||||
getsockopt(server_connection.socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
|
||||
if (error != 0) {
|
||||
log_error("Connection failed %d", error);
|
||||
connectfailed = true;
|
||||
break;
|
||||
}
|
||||
if (SDL_TICKS_PASSED(SDL_GetTicks(), server_connect_time + 3000)) {
|
||||
log_error("Connection timed out.");
|
||||
connectfailed = true;
|
||||
break;
|
||||
}
|
||||
fd_set writeFD;
|
||||
FD_ZERO(&writeFD);
|
||||
FD_SET(server_connection.socket, &writeFD);
|
||||
timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
if (select(server_connection.socket + 1, NULL, &writeFD, NULL, &timeout) > 0) {
|
||||
int error = 0;
|
||||
socklen_t len = sizeof(error);
|
||||
getsockopt(server_connection.socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
|
||||
if (error == 0) {
|
||||
status = NETWORK_STATUS_CONNECTED;
|
||||
Client_Send_AUTH(OPENRCT2_VERSION, gConfigNetwork.player_name, "");
|
||||
window_network_status_open("Authenticating...");
|
||||
}
|
||||
}
|
||||
}break;
|
||||
case NETWORK_STATUS_CONNECTED:
|
||||
if (!ProcessConnection(server_connection)) {
|
||||
window_network_status_open("Connection closed");
|
||||
Close();
|
||||
}
|
||||
ProcessGameCommandQueue();
|
||||
|
||||
// Check synchronisation
|
||||
if (!_desynchronised && !CheckSRAND(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32), RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32))) {
|
||||
_desynchronised = true;
|
||||
window_network_status_open("Network desync detected");
|
||||
if (!gConfigNetwork.stay_connected) {
|
||||
Close();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (connectfailed) {
|
||||
Close();
|
||||
window_network_status_close();
|
||||
window_error_open(STR_UNABLE_TO_CONNECT_TO_SERVER, STR_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1032,6 +1157,11 @@ int network_get_mode()
|
||||
return gNetwork.GetMode();
|
||||
}
|
||||
|
||||
int network_get_status()
|
||||
{
|
||||
return gNetwork.GetStatus();
|
||||
}
|
||||
|
||||
int network_get_authstatus()
|
||||
{
|
||||
return gNetwork.GetAuthStatus();
|
||||
@@ -1125,44 +1255,9 @@ void network_kick_player(int playerId)
|
||||
gNetwork.KickPlayer(playerId);
|
||||
}
|
||||
|
||||
#ifdef USE_INET_PTON
|
||||
static bool network_get_address(char *dst, size_t dstLength, const char *host)
|
||||
{
|
||||
struct addrinfo *remoteHost;
|
||||
|
||||
if (getaddrinfo(host, NULL, NULL, &remoteHost) != 0) {
|
||||
// Failed to resolve host name
|
||||
return false;
|
||||
}
|
||||
|
||||
for (; remoteHost != NULL; remoteHost = remoteHost->ai_next) {
|
||||
if (remoteHost->ai_family != AF_INET) continue;
|
||||
|
||||
struct sockaddr_in *ipv4SockAddr = (struct sockaddr_in*)remoteHost->ai_addr;
|
||||
return inet_ntop(AF_INET, (void*)&ipv4SockAddr->sin_addr, dst, dstLength) != NULL;
|
||||
}
|
||||
|
||||
// No IPv4 addresses found for host name
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
static char *network_getAddress(char *host)
|
||||
{
|
||||
struct hostent *remoteHost;
|
||||
struct in_addr addr;
|
||||
remoteHost = gethostbyname(host);
|
||||
if (remoteHost != NULL && remoteHost->h_addrtype == AF_INET && remoteHost->h_addr_list[0] != 0) {
|
||||
addr.s_addr = *(u_long *)remoteHost->h_addr_list[0];
|
||||
return inet_ntoa(addr);
|
||||
}
|
||||
|
||||
return host;
|
||||
}
|
||||
#endif // USE_INET_PTON
|
||||
|
||||
|
||||
#else
|
||||
int network_get_mode() { return NETWORK_MODE_NONE; }
|
||||
int network_get_status() { return NETWORK_STATUS_NONE; }
|
||||
uint32 network_get_server_tick() { return RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32); }
|
||||
void network_send_gamecmd(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 callback) {}
|
||||
void network_send_map() {}
|
||||
|
||||
@@ -31,6 +31,22 @@ enum {
|
||||
NETWORK_PLAYER_FLAG_ISSERVER = 1 << 0,
|
||||
};
|
||||
|
||||
enum {
|
||||
NETWORK_AUTH_NONE,
|
||||
NETWORK_AUTH_REQUESTED,
|
||||
NETWORK_AUTH_OK,
|
||||
NETWORK_AUTH_BADVERSION,
|
||||
NETWORK_AUTH_BADNAME,
|
||||
NETWORK_AUTH_BADPASSWORD
|
||||
};
|
||||
|
||||
enum {
|
||||
NETWORK_STATUS_NONE,
|
||||
NETWORK_STATUS_RESOLVING,
|
||||
NETWORK_STATUS_CONNECTING,
|
||||
NETWORK_STATUS_CONNECTED
|
||||
};
|
||||
|
||||
#define NETWORK_DEFAULT_PORT 11753
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -44,17 +60,9 @@ extern "C" {
|
||||
|
||||
#ifndef DISABLE_NETWORK
|
||||
|
||||
#ifndef __MINGW32__
|
||||
#define USE_INET_PTON
|
||||
#else
|
||||
#warning using deprecated network functions in lieu of inet_pton, inet_ntop
|
||||
#endif // __MINGW32__
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#ifdef USE_INET_PTON
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
#include <ws2tcpip.h>
|
||||
#define LAST_SOCKET_ERROR() WSAGetLastError()
|
||||
#undef EWOULDBLOCK
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
@@ -72,15 +80,6 @@ extern "C" {
|
||||
#define ioctlsocket ioctl
|
||||
#endif // _WIN32
|
||||
|
||||
enum {
|
||||
NETWORK_AUTH_NONE,
|
||||
NETWORK_AUTH_REQUESTED,
|
||||
NETWORK_AUTH_OK,
|
||||
NETWORK_AUTH_BADVERSION,
|
||||
NETWORK_AUTH_BADNAME,
|
||||
NETWORK_AUTH_BADPASSWORD
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <list>
|
||||
@@ -137,6 +136,7 @@ class NetworkConnection
|
||||
{
|
||||
public:
|
||||
NetworkConnection();
|
||||
~NetworkConnection();
|
||||
int ReadPacket();
|
||||
void QueuePacket(std::unique_ptr<NetworkPacket> packet);
|
||||
void SendQueuedPackets();
|
||||
@@ -155,6 +155,33 @@ private:
|
||||
std::list<std::unique_ptr<NetworkPacket>> outboundpackets;
|
||||
};
|
||||
|
||||
class NetworkAddress
|
||||
{
|
||||
public:
|
||||
NetworkAddress();
|
||||
void Resolve(const char* host, unsigned short port, bool nonblocking = true);
|
||||
int GetResolveStatus(void);
|
||||
|
||||
std::shared_ptr<sockaddr_storage> ss;
|
||||
std::shared_ptr<int> ss_len;
|
||||
|
||||
enum {
|
||||
RESOLVE_NONE,
|
||||
RESOLVE_INPROGRESS,
|
||||
RESOLVE_OK,
|
||||
RESOLVE_FAILED
|
||||
};
|
||||
|
||||
private:
|
||||
static int ResolveFunc(void* pointer);
|
||||
|
||||
const char* host;
|
||||
unsigned short port;
|
||||
SDL_mutex* mutex;
|
||||
SDL_cond* cond;
|
||||
std::shared_ptr<int> status;
|
||||
};
|
||||
|
||||
class Network
|
||||
{
|
||||
public:
|
||||
@@ -163,8 +190,9 @@ public:
|
||||
bool Init();
|
||||
void Close();
|
||||
bool BeginClient(const char* host, unsigned short port);
|
||||
bool BeginServer(unsigned short port);
|
||||
bool BeginServer(unsigned short port, const char* address = NULL);
|
||||
int GetMode();
|
||||
int GetStatus();
|
||||
int GetAuthStatus();
|
||||
uint32 GetServerTick();
|
||||
uint8 GetPlayerID();
|
||||
@@ -211,8 +239,9 @@ private:
|
||||
};
|
||||
|
||||
int mode;
|
||||
int status;
|
||||
NetworkAddress server_address;
|
||||
bool wsa_initialized;
|
||||
SOCKET server_socket;
|
||||
SOCKET listening_socket;
|
||||
NetworkConnection server_connection;
|
||||
uint32 last_tick_sent_time;
|
||||
@@ -226,6 +255,8 @@ private:
|
||||
std::vector<uint8> chunk_buffer;
|
||||
char password[33];
|
||||
bool _desynchronised;
|
||||
uint32 server_connect_time;
|
||||
|
||||
|
||||
void UpdateServer();
|
||||
void UpdateClient();
|
||||
@@ -259,6 +290,7 @@ int network_begin_client(const char *host, int port);
|
||||
int network_begin_server(int port);
|
||||
|
||||
int network_get_mode();
|
||||
int network_get_status();
|
||||
void network_update();
|
||||
int network_get_authstatus();
|
||||
uint32 network_get_server_tick();
|
||||
@@ -276,11 +308,6 @@ void network_send_gamecmd(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32
|
||||
void network_kick_player(int playerId);
|
||||
|
||||
void network_print_error();
|
||||
#ifdef USE_INET_PTON
|
||||
static bool network_get_address(char *dst, size_t dstLength, const char *host);
|
||||
#else
|
||||
static char *network_getAddress(char *host);
|
||||
#endif // USE_INET_PTON
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -524,17 +524,29 @@ static void join_server(char *address, bool spectate)
|
||||
{
|
||||
int port = gConfigNetwork.default_port;
|
||||
|
||||
char *colon = strchr(address, ':');
|
||||
if (colon != NULL) {
|
||||
bool addresscopied = false;
|
||||
|
||||
char *endbracket = strrchr(address, ']');
|
||||
char *startbracket = strrchr(address, '[');
|
||||
char *dot = strchr(address, '.');
|
||||
|
||||
char *colon = strrchr(address, ':');
|
||||
if (colon != NULL && (endbracket != NULL || dot != NULL)) {
|
||||
address = substr(address, colon - address);
|
||||
sscanf(colon + 1, "%d", &port);
|
||||
addresscopied = true;
|
||||
}
|
||||
|
||||
if (startbracket && endbracket) {
|
||||
address = substr(startbracket + 1, endbracket - startbracket - 1);
|
||||
addresscopied = true;
|
||||
}
|
||||
|
||||
if (!network_begin_client(address, port)) {
|
||||
window_error_open(STR_UNABLE_TO_CONNECT_TO_SERVER, STR_NONE);
|
||||
}
|
||||
|
||||
if (colon != NULL) {
|
||||
if (addresscopied) {
|
||||
free(address);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user