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:
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user