refactor NetworkConnection and NetworkPacket

This commit is contained in:
Ted John 2016-05-28 17:54:45 +01:00
parent 46ecd53a99
commit 31ac6e7fdf
8 changed files with 587 additions and 403 deletions

View File

@ -84,7 +84,9 @@
<ClCompile Include="src\network\http.cpp" />
<ClCompile Include="src\network\network.cpp" />
<ClCompile Include="src\network\NetworkAddress.cpp" />
<ClCompile Include="src\network\NetworkConnection.cpp" />
<ClCompile Include="src\network\NetworkKey.cpp" />
<ClCompile Include="src\network\NetworkPacket.cpp" />
<ClCompile Include="src\network\NetworkUser.cpp" />
<ClCompile Include="src\network\twitch.cpp" />
<ClCompile Include="src\object.c" />
@ -360,6 +362,8 @@
<ClInclude Include="src\management\research.h" />
<ClInclude Include="src\network\http.h" />
<ClInclude Include="src\network\NetworkAddress.h" />
<ClInclude Include="src\network\NetworkConnection.h" />
<ClInclude Include="src\network\NetworkPacket.h" />
<ClInclude Include="src\network\NetworkTypes.h" />
<ClInclude Include="src\network\NetworkUser.h" />
<ClInclude Include="src\network\twitch.h" />

View File

@ -0,0 +1,221 @@
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#include "NetworkConnection.h"
#include "../core/String.hpp"
#include <SDL.h>
extern "C"
{
#include "../localisation/localisation.h"
}
constexpr size_t NETWORK_DISCONNECT_REASON_BUFFER_SIZE = 256;
NetworkConnection::NetworkConnection()
{
authstatus = NETWORK_AUTH_NONE;
player = 0;
socket = INVALID_SOCKET;
ResetLastPacketTime();
last_disconnect_reason = nullptr;
}
NetworkConnection::~NetworkConnection()
{
if (socket != INVALID_SOCKET)
{
closesocket(socket);
}
if (last_disconnect_reason)
{
delete[] last_disconnect_reason;
}
}
int NetworkConnection::ReadPacket()
{
if (inboundpacket.transferred < sizeof(inboundpacket.size))
{
// read packet size
int readBytes = recv(socket, &((char*)&inboundpacket.size)[inboundpacket.transferred], sizeof(inboundpacket.size) - inboundpacket.transferred, 0);
if (readBytes == SOCKET_ERROR || readBytes == 0)
{
if (LAST_SOCKET_ERROR() != EWOULDBLOCK && LAST_SOCKET_ERROR() != EAGAIN)
{
return NETWORK_READPACKET_DISCONNECTED;
}
else
{
return NETWORK_READPACKET_NO_DATA;
}
}
inboundpacket.transferred += readBytes;
if (inboundpacket.transferred == sizeof(inboundpacket.size))
{
inboundpacket.size = ntohs(inboundpacket.size);
if (inboundpacket.size == 0) // Can't have a size 0 packet
{
return NETWORK_READPACKET_DISCONNECTED;
}
inboundpacket.data->resize(inboundpacket.size);
}
}
else
{
// read packet data
if (inboundpacket.data->capacity() > 0)
{
int readBytes = recv(socket,
(char*)&inboundpacket.GetData()[inboundpacket.transferred - sizeof(inboundpacket.size)],
sizeof(inboundpacket.size) + inboundpacket.size - inboundpacket.transferred,
0);
if (readBytes == SOCKET_ERROR || readBytes == 0)
{
if (LAST_SOCKET_ERROR() != EWOULDBLOCK && LAST_SOCKET_ERROR() != EAGAIN)
{
return NETWORK_READPACKET_DISCONNECTED;
}
else
{
return NETWORK_READPACKET_NO_DATA;
}
}
inboundpacket.transferred += readBytes;
}
if (inboundpacket.transferred == sizeof(inboundpacket.size) + inboundpacket.size)
{
last_packet_time = SDL_GetTicks();
return NETWORK_READPACKET_SUCCESS;
}
}
return NETWORK_READPACKET_MORE_DATA;
}
bool NetworkConnection::SendPacket(NetworkPacket& packet)
{
uint16 sizen = htons(packet.size);
std::vector<uint8> tosend;
tosend.reserve(sizeof(sizen) + packet.size);
tosend.insert(tosend.end(), (uint8*)&sizen, (uint8*)&sizen + sizeof(sizen));
tosend.insert(tosend.end(), packet.data->begin(), packet.data->end());
while (true)
{
int sentBytes = send(socket, (const char*)&tosend[packet.transferred], tosend.size() - packet.transferred, FLAG_NO_PIPE);
if (sentBytes == SOCKET_ERROR)
{
return false;
}
packet.transferred += sentBytes;
if (packet.transferred == tosend.size())
{
return true;
}
}
return false;
}
void NetworkConnection::QueuePacket(std::unique_ptr<NetworkPacket> packet, bool front)
{
if (authstatus == NETWORK_AUTH_OK || !packet->CommandRequiresAuth())
{
packet->size = (uint16)packet->data->size();
if (front)
{
outboundpackets.push_front(std::move(packet));
}
else
{
outboundpackets.push_back(std::move(packet));
}
}
}
void NetworkConnection::SendQueuedPackets()
{
while (outboundpackets.size() > 0 && SendPacket(*(outboundpackets.front()).get()))
{
outboundpackets.remove(outboundpackets.front());
}
}
bool NetworkConnection::SetTCPNoDelay(bool on)
{
return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on)) == 0;
}
bool NetworkConnection::SetNonBlocking(bool on)
{
return SetNonBlocking(socket, on);
}
bool NetworkConnection::SetNonBlocking(SOCKET socket, bool on)
{
#ifdef __WINDOWS__
u_long nonblocking = on;
return ioctlsocket(socket, FIONBIO, &nonblocking) == 0;
#else
int flags = fcntl(socket, F_GETFL, 0);
return fcntl(socket, F_SETFL, on ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK)) == 0;
#endif
}
void NetworkConnection::ResetLastPacketTime()
{
last_packet_time = SDL_GetTicks();
}
bool NetworkConnection::ReceivedPacketRecently()
{
#ifndef DEBUG
if (SDL_TICKS_PASSED(SDL_GetTicks(), last_packet_time + 7000))
{
return false;
}
#endif
return true;
}
const utf8 * NetworkConnection::getLastDisconnectReason() const
{
return this->last_disconnect_reason;
}
void NetworkConnection::setLastDisconnectReason(const utf8 * src)
{
if (src == nullptr)
{
if (last_disconnect_reason)
{
delete[] last_disconnect_reason;
last_disconnect_reason = nullptr;
}
return;
}
if (last_disconnect_reason == nullptr)
{
last_disconnect_reason = new utf8[NETWORK_DISCONNECT_REASON_BUFFER_SIZE];
}
String::Set(last_disconnect_reason, NETWORK_DISCONNECT_REASON_BUFFER_SIZE, src);
}
void NetworkConnection::setLastDisconnectReason(const rct_string_id string_id, void *args)
{
char buffer[NETWORK_DISCONNECT_REASON_BUFFER_SIZE];
format_string(buffer, string_id, args);
setLastDisconnectReason(buffer);
}

View File

@ -0,0 +1,62 @@
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#pragma once
#include <list>
#include <memory>
#include <vector>
#include "NetworkTypes.h"
#include "NetworkKey.h"
#include "NetworkPacket.h"
#include "../common.h"
class NetworkPlayer;
class NetworkConnection
{
public:
SOCKET socket = INVALID_SOCKET;
NetworkPacket inboundpacket;
NETWORK_AUTH authstatus = NETWORK_AUTH_NONE;
NetworkPlayer * player;
uint32 ping_time = 0;
NetworkKey key;
std::vector<uint8> challenge;
NetworkConnection();
~NetworkConnection();
int ReadPacket();
void QueuePacket(std::unique_ptr<NetworkPacket> packet, bool front = false);
void SendQueuedPackets();
bool SetTCPNoDelay(bool on);
bool SetNonBlocking(bool on);
static bool SetNonBlocking(SOCKET socket, bool on);
void ResetLastPacketTime();
bool ReceivedPacketRecently();
const utf8 * getLastDisconnectReason() const;
void setLastDisconnectReason(const utf8 * src);
void setLastDisconnectReason(const rct_string_id string_id, void * args = nullptr);
private:
utf8 * last_disconnect_reason;
bool SendPacket(NetworkPacket &packet);
std::list<std::unique_ptr<NetworkPacket>> outboundpackets;
uint32 last_packet_time;
};

View File

@ -0,0 +1,114 @@
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#include "NetworkTypes.h"
#include "NetworkPacket.h"
NetworkPacket::NetworkPacket()
{
transferred = 0;
read = 0;
size = 0;
data = std::make_shared<std::vector<uint8>>();
}
std::unique_ptr<NetworkPacket> NetworkPacket::Allocate()
{
return std::unique_ptr<NetworkPacket>(new NetworkPacket); // change to make_unique in c++14
}
std::unique_ptr<NetworkPacket> NetworkPacket::Duplicate(NetworkPacket &packet)
{
return std::unique_ptr<NetworkPacket>(new NetworkPacket(packet)); // change to make_unique in c++14
}
uint8 * NetworkPacket::GetData()
{
return &(*data)[0];
}
uint32 NetworkPacket::GetCommand()
{
if (data->size() >= sizeof(uint32))
{
return ByteSwapBE(*(uint32 *)(&(*data)[0]));
}
else
{
return NETWORK_COMMAND_INVALID;
}
}
void NetworkPacket::Clear()
{
transferred = 0;
read = 0;
data->clear();
}
bool NetworkPacket::CommandRequiresAuth()
{
switch (GetCommand()) {
case NETWORK_COMMAND_PING:
case NETWORK_COMMAND_AUTH:
case NETWORK_COMMAND_TOKEN:
case NETWORK_COMMAND_GAMEINFO:
return false;
default:
return true;
}
}
void NetworkPacket::Write(const uint8 * bytes, uint32 size)
{
data->insert(data->end(), bytes, bytes + size);
}
void NetworkPacket::WriteString(const utf8 * string)
{
Write((uint8 *)string, strlen(string) + 1);
}
const uint8 * NetworkPacket::Read(uint32 size)
{
if (read + size > NetworkPacket::size)
{
return nullptr;
}
else
{
uint8 * data = &GetData()[read];
read += size;
return data;
}
}
const utf8 * NetworkPacket::ReadString()
{
char * str = (char *)&GetData()[read];
char * strend = str;
while (read < size && *strend != 0)
{
read++;
strend++;
}
if (*strend != 0)
{
return nullptr;
}
read++;
return str;
}

View File

@ -0,0 +1,70 @@
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#pragma once
#include <memory>
#include <vector>
#include "../common.h"
class NetworkPacket
{
public:
uint16 size;
std::shared_ptr<std::vector<uint8>> data;
uint32 transferred;
sint32 read;
static std::unique_ptr<NetworkPacket> Allocate();
static std::unique_ptr<NetworkPacket> Duplicate(NetworkPacket& packet);
NetworkPacket();
uint8 * GetData();
uint32 GetCommand();
void Clear();
bool CommandRequiresAuth();
const uint8 * Read(uint32 size);
const utf8 * ReadString();
void Write(const uint8 * bytes, uint32 size);
void WriteString(const utf8 * string);
template <typename T>
NetworkPacket & operator >>(T &value)
{
if (read + sizeof(value) > size)
{
value = 0;
}
else
{
value = ByteSwapBE(*((T *)&GetData()[read]));
read += sizeof(value);
}
return *this;
}
template <typename T>
NetworkPacket & operator <<(T value) {
T swapped = ByteSwapBE(value);
uint8 * bytes = (uint8 *)&swapped;
data->insert(data->end(), bytes, bytes + sizeof(value));
return *this;
}
};

View File

@ -16,12 +16,125 @@
#pragma once
#include <sdl/SDL_endian.h>
#include <sdl/SDL_platform.h>
#ifdef __WINDOWS__
// winsock2 must be included before windows.h
#include <winsock2.h>
#include <ws2tcpip.h>
#define LAST_SOCKET_ERROR() WSAGetLastError()
#undef EWOULDBLOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
#ifndef SHUT_RD
#define SHUT_RD SD_RECEIVE
#endif
#ifndef SHUT_RDWR
#define SHUT_RDWR SD_BOTH
#endif
#define FLAG_NO_PIPE 0
#else
#include <errno.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <fcntl.h>
typedef int SOCKET;
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
#define LAST_SOCKET_ERROR() errno
#define closesocket close
#define ioctlsocket ioctl
#if defined(__LINUX__)
#define FLAG_NO_PIPE MSG_NOSIGNAL
#else
#define FLAG_NO_PIPE 0
#endif // defined(__LINUX__)
#endif // __WINDOWS__
#include "../common.h"
enum NETWORK_READPACKET
{
NETWORK_READPACKET_SUCCESS,
NETWORK_READPACKET_NO_DATA,
NETWORK_READPACKET_MORE_DATA,
NETWORK_READPACKET_DISCONNECTED
};
enum NETWORK_AUTH
{
NETWORK_AUTH_NONE,
NETWORK_AUTH_REQUESTED,
NETWORK_AUTH_OK,
NETWORK_AUTH_BADVERSION,
NETWORK_AUTH_BADNAME,
NETWORK_AUTH_BADPASSWORD,
NETWORK_AUTH_VERIFICATIONFAILURE,
NETWORK_AUTH_FULL,
NETWORK_AUTH_REQUIREPASSWORD,
NETWORK_AUTH_VERIFIED,
NETWORK_AUTH_UNKNOWN_KEY_DISALLOWED,
};
enum NETWORK_COMMAND
{
NETWORK_COMMAND_AUTH,
NETWORK_COMMAND_MAP,
NETWORK_COMMAND_CHAT,
NETWORK_COMMAND_GAMECMD,
NETWORK_COMMAND_TICK,
NETWORK_COMMAND_PLAYERLIST,
NETWORK_COMMAND_PING,
NETWORK_COMMAND_PINGLIST,
NETWORK_COMMAND_SETDISCONNECTMSG,
NETWORK_COMMAND_GAMEINFO,
NETWORK_COMMAND_SHOWERROR,
NETWORK_COMMAND_GROUPLIST,
NETWORK_COMMAND_EVENT,
NETWORK_COMMAND_TOKEN,
NETWORK_COMMAND_MAX,
NETWORK_COMMAND_INVALID = -1
};
#ifdef __cplusplus
template <size_t size>
struct ByteSwapT { };
template <>
struct ByteSwapT<1>
{
static uint8 SwapBE(uint8 value)
{
return value;
}
};
template <>
struct ByteSwapT<2>
{
static uint16 SwapBE(uint16 value)
{
return SDL_SwapBE16(value);
}
};
template <>
struct ByteSwapT<4>
{
static uint32 SwapBE(uint32 value)
{
return SDL_SwapBE32(value);
}
};
template <typename T>
T ByteSwapBE(const T& value)
{
return ByteSwapT<sizeof(T)>::SwapBE(value);
}
#endif

View File

@ -62,32 +62,6 @@ extern "C" {
Network gNetwork;
NetworkActions gNetworkActions;
enum {
NETWORK_READPACKET_SUCCESS,
NETWORK_READPACKET_NO_DATA,
NETWORK_READPACKET_MORE_DATA,
NETWORK_READPACKET_DISCONNECTED
};
enum {
NETWORK_COMMAND_AUTH,
NETWORK_COMMAND_MAP,
NETWORK_COMMAND_CHAT,
NETWORK_COMMAND_GAMECMD,
NETWORK_COMMAND_TICK,
NETWORK_COMMAND_PLAYERLIST,
NETWORK_COMMAND_PING,
NETWORK_COMMAND_PINGLIST,
NETWORK_COMMAND_SETDISCONNECTMSG,
NETWORK_COMMAND_GAMEINFO,
NETWORK_COMMAND_SHOWERROR,
NETWORK_COMMAND_GROUPLIST,
NETWORK_COMMAND_EVENT,
NETWORK_COMMAND_TOKEN,
NETWORK_COMMAND_MAX,
NETWORK_COMMAND_INVALID = -1
};
enum {
ADVERTISE_STATUS_DISABLED,
ADVERTISE_STATUS_UNREGISTERED,
@ -115,94 +89,6 @@ static void network_get_private_key_path(utf8 *buffer, size_t bufferSize, const
static void network_get_public_key_path(utf8 *buffer, size_t bufferSize, const utf8 * playerName, const utf8 * hash);
static void network_get_keymap_path(utf8 *buffer, size_t bufferSize);
NetworkPacket::NetworkPacket()
{
transferred = 0;
read = 0;
size = 0;
data = std::make_shared<std::vector<uint8>>();
}
std::unique_ptr<NetworkPacket> NetworkPacket::Allocate()
{
return std::unique_ptr<NetworkPacket>(new NetworkPacket); // change to make_unique in c++14
}
std::unique_ptr<NetworkPacket> NetworkPacket::Duplicate(NetworkPacket& packet)
{
return std::unique_ptr<NetworkPacket>(new NetworkPacket(packet)); // change to make_unique in c++14
}
uint8* NetworkPacket::GetData()
{
return &(*data)[0];
}
uint32 NetworkPacket::GetCommand()
{
if (data->size() >= sizeof(uint32)) {
return ByteSwapBE(*(uint32*)(&(*data)[0]));
} else {
return NETWORK_COMMAND_INVALID;
}
}
void NetworkPacket::Write(const uint8* bytes, unsigned int size)
{
data->insert(data->end(), bytes, bytes + size);
}
void NetworkPacket::WriteString(const char* string)
{
Write((uint8*)string, strlen(string) + 1);
}
const uint8* NetworkPacket::Read(unsigned int size)
{
if (read + size > NetworkPacket::size) {
return 0;
} else {
uint8* data = &GetData()[read];
read += size;
return data;
}
}
const char* NetworkPacket::ReadString()
{
char* str = (char*)&GetData()[read];
char* strend = str;
while (read < size && *strend != 0) {
read++;
strend++;
}
if (*strend != 0) {
return nullptr;
}
read++;
return str;
}
void NetworkPacket::Clear()
{
transferred = 0;
read = 0;
data->clear();
}
bool NetworkPacket::CommandRequiresAuth()
{
switch (GetCommand()) {
case NETWORK_COMMAND_PING:
case NETWORK_COMMAND_AUTH:
case NETWORK_COMMAND_TOKEN:
case NETWORK_COMMAND_GAMEINFO:
return false;
default:
return true;
}
}
void NetworkPlayer::Read(NetworkPacket& packet)
{
const char* name = packet.ReadString();
@ -371,172 +257,6 @@ void NetworkGroup::SetName(std::string name)
NetworkGroup::name = name;
}
NetworkConnection::NetworkConnection()
{
authstatus = NETWORK_AUTH_NONE;
player = 0;
socket = INVALID_SOCKET;
ResetLastPacketTime();
last_disconnect_reason = NULL;
}
NetworkConnection::~NetworkConnection()
{
if (socket != INVALID_SOCKET) {
closesocket(socket);
}
if (last_disconnect_reason) {
delete[] last_disconnect_reason;
}
}
int NetworkConnection::ReadPacket()
{
if (inboundpacket.transferred < sizeof(inboundpacket.size)) {
// read packet size
int readBytes = recv(socket, &((char*)&inboundpacket.size)[inboundpacket.transferred], sizeof(inboundpacket.size) - inboundpacket.transferred, 0);
if (readBytes == SOCKET_ERROR || readBytes == 0) {
if (LAST_SOCKET_ERROR() != EWOULDBLOCK && LAST_SOCKET_ERROR() != EAGAIN) {
return NETWORK_READPACKET_DISCONNECTED;
} else {
return NETWORK_READPACKET_NO_DATA;
}
}
inboundpacket.transferred += readBytes;
if (inboundpacket.transferred == sizeof(inboundpacket.size)) {
inboundpacket.size = ntohs(inboundpacket.size);
if(inboundpacket.size == 0){ // Can't have a size 0 packet
return NETWORK_READPACKET_DISCONNECTED;
}
inboundpacket.data->resize(inboundpacket.size);
}
} else {
// read packet data
if (inboundpacket.data->capacity() > 0) {
int readBytes = recv(socket, (char*)&inboundpacket.GetData()[inboundpacket.transferred - sizeof(inboundpacket.size)],
sizeof(inboundpacket.size) + inboundpacket.size - inboundpacket.transferred, 0);
if (readBytes == SOCKET_ERROR || readBytes == 0) {
if (LAST_SOCKET_ERROR() != EWOULDBLOCK && LAST_SOCKET_ERROR() != EAGAIN) {
return NETWORK_READPACKET_DISCONNECTED;
} else {
return NETWORK_READPACKET_NO_DATA;
}
}
inboundpacket.transferred += readBytes;
}
if (inboundpacket.transferred == sizeof(inboundpacket.size) + inboundpacket.size) {
last_packet_time = SDL_GetTicks();
return NETWORK_READPACKET_SUCCESS;
}
}
return NETWORK_READPACKET_MORE_DATA;
}
bool NetworkConnection::SendPacket(NetworkPacket& packet)
{
uint16 sizen = htons(packet.size);
std::vector<uint8> tosend;
tosend.reserve(sizeof(sizen) + packet.size);
tosend.insert(tosend.end(), (uint8*)&sizen, (uint8*)&sizen + sizeof(sizen));
tosend.insert(tosend.end(), packet.data->begin(), packet.data->end());
while (1) {
int sentBytes = send(socket, (const char*)&tosend[packet.transferred], tosend.size() - packet.transferred, FLAG_NO_PIPE);
if (sentBytes == SOCKET_ERROR) {
return false;
}
packet.transferred += sentBytes;
if (packet.transferred == tosend.size()) {
return true;
}
}
return false;
}
void NetworkConnection::QueuePacket(std::unique_ptr<NetworkPacket> packet, bool front)
{
if (authstatus == NETWORK_AUTH_OK || !packet->CommandRequiresAuth()) {
packet->size = (uint16)packet->data->size();
if (front) {
outboundpackets.push_front(std::move(packet));
} else {
outboundpackets.push_back(std::move(packet));
}
}
}
void NetworkConnection::SendQueuedPackets()
{
while (outboundpackets.size() > 0 && SendPacket(*(outboundpackets.front()).get())) {
outboundpackets.remove(outboundpackets.front());
}
}
bool NetworkConnection::SetTCPNoDelay(bool on)
{
return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on)) == 0;
}
bool NetworkConnection::SetNonBlocking(bool on)
{
return SetNonBlocking(socket, on);
}
bool NetworkConnection::SetNonBlocking(SOCKET socket, bool on)
{
#ifdef __WINDOWS__
u_long nonblocking = on;
return ioctlsocket(socket, FIONBIO, &nonblocking) == 0;
#else
int flags = fcntl(socket, F_GETFL, 0);
return fcntl(socket, F_SETFL, on ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK)) == 0;
#endif
}
void NetworkConnection::ResetLastPacketTime()
{
last_packet_time = SDL_GetTicks();
}
bool NetworkConnection::ReceivedPacketRecently()
{
#ifndef DEBUG
if (SDL_TICKS_PASSED(SDL_GetTicks(), last_packet_time + 7000)) {
return false;
}
#endif
return true;
}
const char* NetworkConnection::getLastDisconnectReason() const
{
return this->last_disconnect_reason;
}
void NetworkConnection::setLastDisconnectReason(const char *src)
{
if (src == nullptr) {
if (last_disconnect_reason) {
delete[] last_disconnect_reason;
last_disconnect_reason = NULL;
}
return;
}
if (!last_disconnect_reason) {
last_disconnect_reason = new char[NETWORK_DISCONNECT_REASON_BUFFER_SIZE];
}
strncpy(last_disconnect_reason, src, NETWORK_DISCONNECT_REASON_BUFFER_SIZE - 1);
}
void NetworkConnection::setLastDisconnectReason(const rct_string_id string_id, void *args)
{
char buffer[NETWORK_DISCONNECT_REASON_BUFFER_SIZE];
format_string(buffer, string_id, args);
setLastDisconnectReason(buffer);
}
Network::Network()
{
wsa_initialized = false;

View File

@ -27,20 +27,6 @@ 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,
NETWORK_AUTH_VERIFICATIONFAILURE,
NETWORK_AUTH_FULL,
NETWORK_AUTH_REQUIREPASSWORD,
NETWORK_AUTH_VERIFIED,
NETWORK_AUTH_UNKNOWN_KEY_DISALLOWED,
};
enum {
NETWORK_STATUS_NONE,
NETWORK_STATUS_READY,
@ -70,40 +56,7 @@ extern "C" {
#define NETWORK_STREAM_VERSION "9"
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
#define NETWORK_DISCONNECT_REASON_BUFFER_SIZE 256
#ifdef __WINDOWS__
#include <winsock2.h>
#include <ws2tcpip.h>
#define LAST_SOCKET_ERROR() WSAGetLastError()
#undef EWOULDBLOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
#ifndef SHUT_RD
#define SHUT_RD SD_RECEIVE
#endif
#ifndef SHUT_RDWR
#define SHUT_RDWR SD_BOTH
#endif
#define FLAG_NO_PIPE 0
#else
#include <errno.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <fcntl.h>
typedef int SOCKET;
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
#define LAST_SOCKET_ERROR() errno
#define closesocket close
#define ioctlsocket ioctl
#if defined(__LINUX__)
#define FLAG_NO_PIPE MSG_NOSIGNAL
#else
#define FLAG_NO_PIPE 0
#endif // defined(__LINUX__)
#endif // __WINDOWS__
#include "NetworkTypes.h"
// Fixes issues on OS X
#if defined(_RCT2_H_) && !defined(_MSC_VER)
@ -124,51 +77,11 @@ extern "C" {
#include "../core/Json.hpp"
#include "../core/Nullable.hpp"
#include "NetworkAddress.h"
#include "NetworkConnection.h"
#include "NetworkKey.h"
#include "NetworkPacket.h"
#include "NetworkUser.h"
template <std::size_t size>
struct ByteSwapT { };
template <>
struct ByteSwapT<1> { static uint8 SwapBE(uint8 value) { return value; } };
template <>
struct ByteSwapT<2> { static uint16 SwapBE(uint16 value) { return SDL_SwapBE16(value); } };
template <>
struct ByteSwapT<4> { static uint32 SwapBE(uint32 value) { return SDL_SwapBE32(value); } };
template <typename T>
T ByteSwapBE(const T& value) { return ByteSwapT<sizeof(T)>::SwapBE(value); }
class NetworkPacket
{
public:
NetworkPacket();
static std::unique_ptr<NetworkPacket> Allocate();
static std::unique_ptr<NetworkPacket> Duplicate(NetworkPacket& packet);
uint8* GetData();
uint32 GetCommand();
template <typename T>
NetworkPacket& operator<<(T value) {
T swapped = ByteSwapBE(value); uint8* bytes = (uint8*)&swapped; data->insert(data->end(), bytes, bytes + sizeof(value));
return *this;
}
void Write(const uint8* bytes, unsigned int size);
void WriteString(const char* string);
template <typename T>
NetworkPacket& operator>>(T& value) {
if (read + sizeof(value) > size) { value = 0; } else { value = ByteSwapBE(*((T*)&GetData()[read])); read += sizeof(value); }
return *this;
}
const uint8* Read(unsigned int size);
const char* ReadString();
void Clear();
bool CommandRequiresAuth();
uint16 size;
std::shared_ptr<std::vector<uint8>> data;
unsigned int transferred;
int read;
};
class NetworkPlayer
{
public:
@ -283,39 +196,6 @@ private:
std::string name;
};
class NetworkConnection
{
public:
NetworkConnection();
~NetworkConnection();
int ReadPacket();
void QueuePacket(std::unique_ptr<NetworkPacket> packet, bool front = false);
void SendQueuedPackets();
bool SetTCPNoDelay(bool on);
bool SetNonBlocking(bool on);
static bool SetNonBlocking(SOCKET socket, bool on);
void ResetLastPacketTime();
bool ReceivedPacketRecently();
const char *getLastDisconnectReason() const;
void setLastDisconnectReason(const char *src);
void setLastDisconnectReason(const rct_string_id string_id, void *args = nullptr);
SOCKET socket = INVALID_SOCKET;
NetworkPacket inboundpacket;
int authstatus = NETWORK_AUTH_NONE;
NetworkPlayer* player;
uint32 ping_time = 0;
NetworkKey key;
std::vector<uint8> challenge;
private:
char* last_disconnect_reason;
bool SendPacket(NetworkPacket& packet);
std::list<std::unique_ptr<NetworkPacket>> outboundpackets;
uint32 last_packet_time;
};
class Network
{
public: