summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/network/core/tcp.cpp27
-rw-r--r--src/network/core/tcp.h2
-rw-r--r--src/network/network.cpp106
-rw-r--r--src/network/network_client.cpp113
-rw-r--r--src/network/network_client.h5
-rw-r--r--src/network/network_content.cpp18
-rw-r--r--src/network/network_internal.h1
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);