diff --git a/src/network/network.cpp b/src/network/network.cpp index 5198e846c6..2c9add27e3 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -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 _chunkBuffer; static NetworkConnection _serverConnection; -static NetworkConnection _clientConnection; +static std::list> _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::unique_ptr NetworkPacket::AllocatePacket() +{ + return std::move(std::make_unique()); +} + +std::unique_ptr NetworkPacket::DuplicatePacket(NetworkPacket& packet) +{ + return std::move(std::make_unique(packet)); +} + uint8* NetworkPacket::GetData() { return &(*data)[0]; @@ -139,11 +150,6 @@ void NetworkConnection::QueuePacket(std::unique_ptr packet) outboundpackets.push_back(std::move(packet)); } -std::unique_ptr NetworkConnection::AllocatePacket() -{ - return std::move(std::unique_ptr(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->socket = socket; + _clientConnectionList.push_back(std::move(networkconnection)); +} + +void network_remove_client(std::unique_ptr& 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 packet = _clientConnection.AllocatePacket(); + std::unique_ptr 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 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 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 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 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 packet = networkconnection.AllocatePacket(); + std::unique_ptr 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 packet = networkconnection.AllocatePacket(); + std::unique_ptr 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() diff --git a/src/network/network.h b/src/network/network.h index e969b38501..05c12a7cd2 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -35,6 +35,8 @@ class NetworkPacket { public: NetworkPacket(); + static std::unique_ptr AllocatePacket(); + static std::unique_ptr DuplicatePacket(NetworkPacket& packet); uint8* GetData(); template 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 packet); - std::unique_ptr AllocatePacket(); void SendQueuedPackets(); SOCKET socket;