1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-06 06:32:56 +01:00

allow multiple client connections

This commit is contained in:
zsilencer
2015-07-07 19:21:05 -06:00
parent 21334e307c
commit 802ccfd98e
2 changed files with 121 additions and 70 deletions

View File

@@ -43,12 +43,13 @@ uint32 gNetworkServerTick = 0;
static network_packet* _packetQueue = NULL;
static int _wsaInitialised = 0;
static WSADATA _wsaData;
static SOCKET _serverSocket;
static SOCKET _clientSocket;
static SOCKET _listeningSocket = INVALID_SOCKET;
static SOCKET _serverSocket = INVALID_SOCKET;
static SOCKET _clientSocket = INVALID_SOCKET;
static network_packet _inboundPacket;
static std::vector<uint8> _chunkBuffer;
static NetworkConnection _serverConnection;
static NetworkConnection _clientConnection;
static std::list<std::unique_ptr<NetworkConnection>> _clientConnectionList;
static void network_process_packet(NetworkPacket& packet);
static int network_send_packet(network_packet *packet);
@@ -61,6 +62,16 @@ NetworkPacket::NetworkPacket()
data = std::make_shared<std::vector<uint8>>();
}
std::unique_ptr<NetworkPacket> NetworkPacket::AllocatePacket()
{
return std::move(std::make_unique<NetworkPacket>());
}
std::unique_ptr<NetworkPacket> NetworkPacket::DuplicatePacket(NetworkPacket& packet)
{
return std::move(std::make_unique<NetworkPacket>(packet));
}
uint8* NetworkPacket::GetData()
{
return &(*data)[0];
@@ -139,11 +150,6 @@ void NetworkConnection::QueuePacket(std::unique_ptr<NetworkPacket> packet)
outboundpackets.push_back(std::move(packet));
}
std::unique_ptr<NetworkPacket> NetworkConnection::AllocatePacket()
{
return std::move(std::unique_ptr<NetworkPacket>(new NetworkPacket)); // can be converted to make_unique in C++14
}
void NetworkConnection::SendQueuedPackets()
{
while (outboundpackets.size() > 0 && SendPacket(*(outboundpackets.front()).get())) {
@@ -225,7 +231,6 @@ void network_end_client()
int network_begin_server(int port)
{
SOCKET listeningSocket;
SOCKADDR_IN localAddress;
u_long iMode;
@@ -233,47 +238,36 @@ int network_begin_server(int port)
return 0;
log_verbose("Begin listening for clients");
listeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listeningSocket == INVALID_SOCKET) {
_listeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (_listeningSocket == INVALID_SOCKET) {
log_error("Unable to create socket.");
return 0;
}
localAddress.sin_family = AF_INET;
localAddress.sin_addr.S_un.S_addr = INADDR_ANY;
localAddress.sin_port = htons(port);
if (bind(listeningSocket, (SOCKADDR*)&localAddress, sizeof(SOCKADDR_IN)) != 0) {
closesocket(listeningSocket);
if (bind(_listeningSocket, (SOCKADDR*)&localAddress, sizeof(SOCKADDR_IN)) != 0) {
closesocket(_listeningSocket);
log_error("Unable to bind to socket.");
return 0;
}
if (listen(listeningSocket, SOMAXCONN) != 0) {
closesocket(listeningSocket);
if (listen(_listeningSocket, SOMAXCONN) != 0) {
closesocket(_listeningSocket);
log_error("Unable to listen on socket.");
return 0;
}
printf("Waiting for client...\n");
_clientSocket = accept(listeningSocket, NULL, NULL);
if (_clientSocket == INVALID_SOCKET) {
closesocket(listeningSocket);
log_error("Failed to accept client.");
iMode = 1;
if (ioctlsocket(_listeningSocket, FIONBIO, &iMode) != NO_ERROR) {
closesocket(_listeningSocket);
log_error("Failed to set non-blocking mode.");
return 0;
}
closesocket(listeningSocket);
iMode = 1;
if (ioctlsocket(_clientSocket, FIONBIO, &iMode) != NO_ERROR) {
closesocket(_clientSocket);
log_error("Failed to set non-blocking mode.");
}
printf("Connected to client!\n");
_clientConnection.socket = _clientSocket;
printf("Ready for clients...\n");
gNetworkStatus = NETWORK_SERVER;
return 1;
@@ -285,16 +279,23 @@ void network_end_server()
closesocket(_clientSocket);
}
void network_update()
void network_add_client(SOCKET socket)
{
printf("New client connection\n");
auto networkconnection = std::make_unique<NetworkConnection>();
networkconnection->socket = socket;
_clientConnectionList.push_back(std::move(networkconnection));
}
void network_remove_client(std::unique_ptr<NetworkConnection>& networkconnection)
{
printf("Client removed\n");
_clientConnectionList.remove(networkconnection);
}
int network_process_connection(NetworkConnection& networkconnection)
{
int packetStatus;
static uint32 lastTickUpdate = 0;
if (gNetworkStatus == NETWORK_NONE)
return;
NetworkConnection& networkconnection = gNetworkStatus == NETWORK_CLIENT ? _serverConnection : _clientConnection;
do {
packetStatus = networkconnection.ReadPacket();
switch(packetStatus) {
@@ -303,11 +304,10 @@ void network_update()
if (gNetworkStatus == NETWORK_CLIENT) {
network_end_client();
printf("Server disconnected...\n");
return;
return 0;
} else if (gNetworkStatus == NETWORK_SERVER) {
network_end_server();
printf("Client disconnected...\n");
return;
return 0;
}
break;
case NETWORK_SUCCESS:
@@ -321,15 +321,48 @@ void network_update()
break;
}
} while (packetStatus == NETWORK_MORE_DATA || packetStatus == NETWORK_SUCCESS);
networkconnection.SendQueuedPackets();
return 1;
}
if (gNetworkStatus == NETWORK_SERVER) {
void network_update()
{
static uint32 lastTickUpdate = 0;
u_long iMode;
if (gNetworkStatus == NETWORK_NONE)
return;
if (gNetworkStatus == NETWORK_CLIENT) {
network_process_connection(_serverConnection);
} else {
for(auto it = _clientConnectionList.begin(); it != _clientConnectionList.end(); it++) {
if (!network_process_connection(*(*it))) {
network_remove_client((*it));
it = _clientConnectionList.begin();
}
}
if (SDL_GetTicks() - lastTickUpdate >= 100) {
lastTickUpdate = SDL_GetTicks();
network_send_tick();
}
SOCKET socket = accept(_listeningSocket, NULL, NULL);
if (socket == INVALID_SOCKET) {
if (WSAGetLastError() != WSAEWOULDBLOCK) {
network_print_error();
closesocket(_listeningSocket);
log_error("Failed to accept client.");
}
} else {
iMode = 1;
if (ioctlsocket(socket, FIONBIO, &iMode) != NO_ERROR) {
closesocket(socket);
log_error("Failed to set non-blocking mode.");
} else {
network_add_client(socket);
}
}
}
networkconnection.SendQueuedPackets();
}
static void network_process_packet(NetworkPacket& packet)
@@ -392,45 +425,56 @@ static void network_process_packet(NetworkPacket& packet)
void network_send_tick()
{
std::unique_ptr<NetworkPacket> packet = _clientConnection.AllocatePacket();
std::unique_ptr<NetworkPacket> packet = NetworkPacket::AllocatePacket();
packet->Write((uint32)NETWORK_COMMAND_TICK);
packet->Write((uint32)RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32));
_clientConnection.QueuePacket(std::move(packet));
for(auto it = _clientConnectionList.begin(); it != _clientConnectionList.end(); it++) {
(*it)->QueuePacket(NetworkPacket::DuplicatePacket(*packet));
}
}
void network_send_map()
{
int buffersize = 0x600000;
std::vector<uint8> buffer(buffersize);
SDL_RWops* rw = SDL_RWFromMem(&buffer[0], buffersize);
scenario_save(rw, 0);
int size = (int)SDL_RWtell(rw);
int chunksize = 1000;
for (int i = 0; i < size; i += chunksize) {
int datasize = min(chunksize, size - i);
std::unique_ptr<NetworkPacket> packet = _clientConnection.AllocatePacket();
packet->Write((uint32)NETWORK_COMMAND_MAP);
packet->Write((uint32)size);
packet->Write((uint32)i);
packet->Write(&buffer[i], datasize);
_clientConnection.QueuePacket(std::move(packet));
if (gNetworkStatus == NETWORK_SERVER) {
int buffersize = 0x600000;
std::vector<uint8> buffer(buffersize);
SDL_RWops* rw = SDL_RWFromMem(&buffer[0], buffersize);
scenario_save(rw, 0);
int size = (int)SDL_RWtell(rw);
int chunksize = 1000;
for (int i = 0; i < size; i += chunksize) {
int datasize = min(chunksize, size - i);
std::unique_ptr<NetworkPacket> packet = NetworkPacket::AllocatePacket();
packet->Write((uint32)NETWORK_COMMAND_MAP);
packet->Write((uint32)size);
packet->Write((uint32)i);
packet->Write(&buffer[i], datasize);
for(auto it = _clientConnectionList.begin(); it != _clientConnectionList.end(); it++) {
(*it)->QueuePacket(NetworkPacket::DuplicatePacket(*packet));
}
}
SDL_RWclose(rw);
}
SDL_RWclose(rw);
}
void network_send_chat(const char* text)
{
NetworkConnection& networkconnection = gNetworkStatus == NETWORK_CLIENT ? _serverConnection : _clientConnection;
std::unique_ptr<NetworkPacket> packet = networkconnection.AllocatePacket();
std::unique_ptr<NetworkPacket> packet = NetworkPacket::AllocatePacket();
packet->Write((uint32)NETWORK_COMMAND_CHAT);
packet->Write((uint8*)text, strlen(text) + 1);
networkconnection.QueuePacket(std::move(packet));
if (gNetworkStatus == NETWORK_SERVER) {
for(auto it = _clientConnectionList.begin(); it != _clientConnectionList.end(); it++) {
(*it)->QueuePacket(NetworkPacket::DuplicatePacket(*packet));
}
} else {
_serverConnection.QueuePacket(std::move(packet));
}
}
void network_send_gamecmd(uint32 command, uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp)
{
NetworkConnection& networkconnection = gNetworkStatus == NETWORK_CLIENT ? _serverConnection : _clientConnection;
std::unique_ptr<NetworkPacket> packet = networkconnection.AllocatePacket();
std::unique_ptr<NetworkPacket> packet = NetworkPacket::AllocatePacket();
packet->Write((uint32)NETWORK_COMMAND_GAMECMD);
packet->Write((uint32)command);
packet->Write((uint32)eax);
@@ -440,7 +484,13 @@ void network_send_gamecmd(uint32 command, uint32 eax, uint32 ebx, uint32 ecx, ui
packet->Write((uint32)esi);
packet->Write((uint32)edi);
packet->Write((uint32)ebp);
networkconnection.QueuePacket(std::move(packet));
if (gNetworkStatus == NETWORK_SERVER) {
for(auto it = _clientConnectionList.begin(); it != _clientConnectionList.end(); it++) {
(*it)->QueuePacket(NetworkPacket::DuplicatePacket(*packet));
}
} else {
_serverConnection.QueuePacket(std::move(packet));
}
}
void network_print_error()

View File

@@ -35,6 +35,8 @@ class NetworkPacket
{
public:
NetworkPacket();
static std::unique_ptr<NetworkPacket> AllocatePacket();
static std::unique_ptr<NetworkPacket> DuplicatePacket(NetworkPacket& packet);
uint8* GetData();
template <class T>
void Write(T value) { uint8* bytes = (uint8*)&value; data->insert(data->end(), bytes, bytes + sizeof(value)); }
@@ -50,7 +52,6 @@ class NetworkConnection
public:
int ReadPacket();
void QueuePacket(std::unique_ptr<NetworkPacket> packet);
std::unique_ptr<NetworkPacket> AllocatePacket();
void SendQueuedPackets();
SOCKET socket;