diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/network/core/tcp.cpp | 27 | ||||
-rw-r--r-- | src/network/core/tcp.h | 2 | ||||
-rw-r--r-- | src/network/network.cpp | 106 | ||||
-rw-r--r-- | src/network/network_client.cpp | 113 | ||||
-rw-r--r-- | src/network/network_client.h | 5 | ||||
-rw-r--r-- | src/network/network_content.cpp | 18 | ||||
-rw-r--r-- | src/network/network_internal.h | 1 |
7 files changed, 161 insertions, 111 deletions
diff --git a/src/network/core/tcp.cpp b/src/network/core/tcp.cpp index 39f90569f..cdf072cec 100644 --- a/src/network/core/tcp.cpp +++ b/src/network/core/tcp.cpp @@ -214,4 +214,31 @@ bool NetworkTCPSocketHandler::IsPacketQueueEmpty() return this->packet_queue == NULL; } +/** + * Check whether this socket can send or receive something. + * @return \c true when there is something to receive. + * @note Sets #writeable if more data can be sent. + */ +bool NetworkTCPSocketHandler::CanSendReceive() +{ + fd_set read_fd, write_fd; + struct timeval tv; + + FD_ZERO(&read_fd); + FD_ZERO(&write_fd); + + FD_SET(this->sock, &read_fd); + FD_SET(this->sock, &write_fd); + + tv.tv_sec = tv.tv_usec = 0; // don't block at all. +#if !defined(__MORPHOS__) && !defined(__AMIGA__) + select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv); +#else + WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL); +#endif + + this->writable = !!FD_ISSET(this->sock, &write_fd); + return FD_ISSET(this->sock, &read_fd); +} + #endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp.h b/src/network/core/tcp.h index b9866cc4e..86c568edf 100644 --- a/src/network/core/tcp.h +++ b/src/network/core/tcp.h @@ -41,6 +41,8 @@ public: Packet *Recv_Packet(); + bool CanSendReceive(); + NetworkTCPSocketHandler(SOCKET s = INVALID_SOCKET); ~NetworkTCPSocketHandler(); }; diff --git a/src/network/network.cpp b/src/network/network.cpp index 308bd7873..fd9771cba 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -240,7 +240,7 @@ uint NetworkCalculateLag(const NetworkClientSocket *cs) /* There was a non-recoverable error, drop back to the main menu with a nice * error */ -static void NetworkError(StringID error_string) +void NetworkError(StringID error_string) { _switch_mode = SM_MENU; extern StringID _switch_mode_errorstr; @@ -253,40 +253,6 @@ static void ServerStartError(const char *error) NetworkError(STR_NETWORK_ERROR_SERVER_START); } -static void NetworkClientError(NetworkRecvStatus res, NetworkClientSocket *cs) -{ - /* First, send a CLIENT_ERROR to the server, so he knows we are - * disconnection (and why!) */ - NetworkErrorCode errorno; - - /* We just want to close the connection.. */ - if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) { - cs->NetworkSocketHandler::CloseConnection(); - cs->CloseConnection(res); - _networking = false; - - DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); - return; - } - - switch (res) { - case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break; - case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break; - case NETWORK_RECV_STATUS_NEWGRF_MISMATCH: errorno = NETWORK_ERROR_NEWGRF_MISMATCH; break; - default: errorno = NETWORK_ERROR_GENERAL; break; - } - - /* This means we fucked up and the server closed the connection */ - if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL && - res != NETWORK_RECV_STATUS_SERVER_BANNED) { - MyClient::SendError(errorno); - } - - _switch_mode = SM_MENU; - cs->CloseConnection(res); - _networking = false; -} - /** * Retrieve the string id of an internal error number * @param err NetworkErrorCode @@ -838,6 +804,9 @@ void NetworkDisconnect(bool blocking) */ static bool NetworkReceive() { + if (!_network_server) { + return ClientNetworkGameSocketHandler::Receive(); + } NetworkClientSocket *cs; fd_set read_fd, write_fd; struct timeval tv; @@ -872,22 +841,7 @@ static bool NetworkReceive() FOR_ALL_CLIENT_SOCKETS(cs) { cs->writable = !!FD_ISSET(cs->sock, &write_fd); if (FD_ISSET(cs->sock, &read_fd)) { - if (_network_server) { - cs->Recv_Packets(); - } else { - NetworkRecvStatus res; - - /* The client already was quiting! */ - if (cs->HasClientQuit()) return false; - - res = cs->Recv_Packets(); - if (res != NETWORK_RECV_STATUS_OKAY) { - /* The client made an error of which we can not recover - * close the client and drop back to main menu */ - NetworkClientError(res, cs); - return false; - } - } + cs->Recv_Packets(); } } return _networking; @@ -896,6 +850,11 @@ static bool NetworkReceive() /* This sends all buffered commands (if possible) */ static void NetworkSend() { + if (!_network_server) { + ClientNetworkGameSocketHandler::Send(); + return; + } + NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->writable) { @@ -909,47 +868,6 @@ static void NetworkSend() } } -static bool NetworkDoClientLoop() -{ - _frame_counter++; - - NetworkExecuteLocalCommandQueue(); - - StateGameLoop(); - - /* Check if we are in sync! */ - if (_sync_frame != 0) { - if (_sync_frame == _frame_counter) { -#ifdef NETWORK_SEND_DOUBLE_SEED - if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) { -#else - if (_sync_seed_1 != _random.state[0]) { -#endif - NetworkError(STR_NETWORK_ERROR_DESYNC); - DEBUG(desync, 1, "sync_err: %08x; %02x", _date, _date_fract); - DEBUG(net, 0, "Sync error detected!"); - NetworkClientError(NETWORK_RECV_STATUS_DESYNC, NetworkClientSocket::Get(0)); - return false; - } - - /* If this is the first time we have a sync-frame, we - * need to let the server know that we are ready and at the same - * frame as he is.. so we can start playing! */ - if (_network_first_time) { - _network_first_time = false; - MyClient::SendAck(); - } - - _sync_frame = 0; - } else if (_sync_frame < _frame_counter) { - DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter); - _sync_frame = 0; - } - } - - return true; -} - /* We have to do some UDP checking */ void NetworkUDPGameLoop() { @@ -1107,11 +1025,11 @@ void NetworkGameLoop() /* Make sure we are at the frame were the server is (quick-frames) */ if (_frame_counter_server > _frame_counter) { while (_frame_counter_server > _frame_counter) { - if (!NetworkDoClientLoop()) break; + if (!ClientNetworkGameSocketHandler::GameLoop()) break; } } else { /* Else, keep on going till _frame_counter_max */ - if (_frame_counter_max > _frame_counter) NetworkDoClientLoop(); + if (_frame_counter_max > _frame_counter) ClientNetworkGameSocketHandler::GameLoop(); } } diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 929d58763..5a930d74b 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -25,6 +25,8 @@ #include "../company_func.h" #include "../company_base.h" #include "../company_gui.h" +#include "../core/random_func.hpp" +#include "../date_func.h" #include "../rev.h" #include "network.h" #include "network_base.h" @@ -73,6 +75,117 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvSta return status; } +/** + * Handle an error coming from the client side. + * @param res The "error" that happened. + */ +void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res) +{ + /* First, send a CLIENT_ERROR to the server, so he knows we are + * disconnection (and why!) */ + NetworkErrorCode errorno; + + /* We just want to close the connection.. */ + if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) { + this->NetworkSocketHandler::CloseConnection(); + this->CloseConnection(res); + _networking = false; + + DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); + return; + } + + switch (res) { + case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break; + case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break; + case NETWORK_RECV_STATUS_NEWGRF_MISMATCH: errorno = NETWORK_ERROR_NEWGRF_MISMATCH; break; + default: errorno = NETWORK_ERROR_GENERAL; break; + } + + /* This means we fucked up and the server closed the connection */ + if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL && + res != NETWORK_RECV_STATUS_SERVER_BANNED) { + SendError(errorno); + } + + _switch_mode = SM_MENU; + this->CloseConnection(res); + _networking = false; +} + + +/** + * Check whether we received/can send some data from/to the server and + * when that's the case handle it appropriately. + * @return true when everything went okay. + */ +/*static */ bool ClientNetworkGameSocketHandler::Receive() +{ + if (my_client->CanSendReceive()) { + NetworkRecvStatus res = my_client->Recv_Packets(); + if (res != NETWORK_RECV_STATUS_OKAY) { + /* The client made an error of which we can not recover + * close the client and drop back to main menu */ + my_client->ClientError(res); + return false; + } + } + return _networking; +} + +/** Send the packets of this socket handler. */ +/*static */ void ClientNetworkGameSocketHandler::Send() +{ + my_client->Send_Packets(); +} + +/** + * Actual game loop for the client. + * @return Whether everything went okay, or not. + */ +/* static */ bool ClientNetworkGameSocketHandler::GameLoop() +{ + _frame_counter++; + + NetworkExecuteLocalCommandQueue(); + + extern void StateGameLoop(); + StateGameLoop(); + + /* Check if we are in sync! */ + if (_sync_frame != 0) { + if (_sync_frame == _frame_counter) { +#ifdef NETWORK_SEND_DOUBLE_SEED + if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) { +#else + if (_sync_seed_1 != _random.state[0]) { +#endif + NetworkError(STR_NETWORK_ERROR_DESYNC); + DEBUG(desync, 1, "sync_err: %08x; %02x", _date, _date_fract); + DEBUG(net, 0, "Sync error detected!"); + my_client->ClientError(NETWORK_RECV_STATUS_DESYNC); + return false; + } + + /* If this is the first time we have a sync-frame, we + * need to let the server know that we are ready and at the same + * frame as he is.. so we can start playing! */ + if (_network_first_time) { + _network_first_time = false; + SendAck(); + } + + _sync_frame = 0; + } else if (_sync_frame < _frame_counter) { + DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter); + _sync_frame = 0; + } + } + + return true; +} + + /** Our client's connection. */ ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = NULL; diff --git a/src/network/network_client.h b/src/network/network_client.h index 5b00aba0f..d8884e037 100644 --- a/src/network/network_client.h +++ b/src/network/network_client.h @@ -54,6 +54,7 @@ public: ~ClientNetworkGameSocketHandler(); NetworkRecvStatus CloseConnection(NetworkRecvStatus status); + void ClientError(NetworkRecvStatus res); static NetworkRecvStatus SendCompanyInformationQuery(); @@ -71,6 +72,10 @@ public: static NetworkRecvStatus SendSetName(const char *name); static NetworkRecvStatus SendRCon(const char *password, const char *command); static NetworkRecvStatus SendMove(CompanyID company, const char *password); + + static void Send(); + static bool Receive(); + static bool GameLoop(); }; typedef ClientNetworkGameSocketHandler MyClient; diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index 95d0966c8..680dbfb98 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -737,27 +737,11 @@ void ClientNetworkContentSocketHandler::SendReceive() return; } - fd_set read_fd, write_fd; - struct timeval tv; - - FD_ZERO(&read_fd); - FD_ZERO(&write_fd); - - FD_SET(this->sock, &read_fd); - FD_SET(this->sock, &write_fd); - - tv.tv_sec = tv.tv_usec = 0; // don't block at all. -#if !defined(__MORPHOS__) && !defined(__AMIGA__) - select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv); -#else - WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL); -#endif - if (FD_ISSET(this->sock, &read_fd)) { + if (this->CanSendReceive()) { this->Recv_Packets(); this->lastActivity = _realtime_tick; } - this->writable = !!FD_ISSET(this->sock, &write_fd); this->Send_Packets(); } diff --git a/src/network/network_internal.h b/src/network/network_internal.h index c4ef68dda..03ac8757d 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -166,6 +166,7 @@ void NetworkFreeLocalCommandQueue(); void NetworkSyncCommandQueue(NetworkClientSocket *cs); /* from network.c */ +void NetworkError(StringID error_string); void NetworkTextMessage(NetworkAction action, ConsoleColour colour, bool self_send, const char *name, const char *str = "", int64 data = 0); void NetworkGetClientName(char *clientname, size_t size, const NetworkClientSocket *cs); uint NetworkCalculateLag(const NetworkClientSocket *cs); |