Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStijn Buys <ingar@osirion.org>2008-03-23 18:12:56 +0000
committerStijn Buys <ingar@osirion.org>2008-03-23 18:12:56 +0000
commit22e136d88817b64ec904a7e7232a2cf9e80e74bd (patch)
treeea369bba78930ff55325412760d14102d326f85b
parent8485d43feca5597c4b412c6912aadcd9586e3cde (diff)
improved network connection handling, keep alive and time out
-rw-r--r--README25
-rw-r--r--osirion.kdevelop.pcsbin518254 -> 514385 bytes
-rw-r--r--osirion.kdevses8
-rw-r--r--src/client/console.cc2
-rw-r--r--src/client/view.cc13
-rw-r--r--src/core/application.cc5
-rw-r--r--src/core/gameconnection.cc2
-rw-r--r--src/core/gameinterface.cc21
-rw-r--r--src/core/gameserver.cc3
-rw-r--r--src/core/net.h4
-rw-r--r--src/core/netclient.cc30
-rw-r--r--src/core/netclient.h3
-rw-r--r--src/core/netconnection.cc53
-rw-r--r--src/core/netconnection.h10
-rw-r--r--src/core/netserver.cc47
-rw-r--r--src/core/player.cc16
-rw-r--r--src/core/player.h3
17 files changed, 173 insertions, 72 deletions
diff --git a/README b/README
index 6610a90..6a88cca 100644
--- a/README
+++ b/README
@@ -7,11 +7,6 @@ The Osirion Project - README
Read INSTALL for instructions on building, installing and udpating.
-Dedicated server
-
- By default, the dedicated server will accept incoming connections
- on UDP port 8042. There is no server console.
-
Client
Starting the client will show the loader screen.
@@ -25,7 +20,7 @@ Client
This wil allow remote players to connect to your client.
To connect to a dedicated server, type 'connect address', where
- adress is the hostname of IP address of the remote server.
+ adress is the hostname or IP address of the remote server.
In-game, you can purchase a new ship with the 'buy' command.
@@ -56,6 +51,7 @@ Console functions
join join the game
spectate spectate
buy purchase a new ship
+ who list connected players
To change the video resolution, set the r_width and
r_height variables and execute r_restart.
@@ -72,8 +68,8 @@ Console functions
r_restart
You can set your name and player color through the cl_color
- and cl_name variables. You will have to disconnect and reconnect
- for the changes to take effect:
+ and cl_name variables. Note that the color if your ship
+ won't change until you buy a new one.
cl_name SpaceCowboy
cl_color 1.0 1.0 0.0
@@ -86,6 +82,16 @@ Configuration
server reads its configuration from server.ini, the client
will use client.ini.
+Dedicated server
+
+ By default, the dedicated server will accept incoming connections
+ on UDP port 8042. There is no server console.
+
+ If you have trouble connecting, try editing the server configuration
+ file ~/.osirion/base/server.ini and change the net_server setting to
+ the server's actual IP address. The default listening port can
+ be altered by changing the net_port setting.
+
Organization of the distribution
C++ source code
@@ -161,6 +167,7 @@ Project contributors
Thorn[mDc] - Canasta and Sharkan ship models
Alpha testing
+
Josky=KCT= - Shuttle ship model
IRC
@@ -185,7 +192,7 @@ Acknowledgements
The Satgnu crew
- Thanks to bobke, blaze-x and Thorn[mDc]
+ Thanks to bobke and blaze-x
DVSoftware for bandwidth, diskpace and CPU power
diff --git a/osirion.kdevelop.pcs b/osirion.kdevelop.pcs
index b0fd24b..02ebf51 100644
--- a/osirion.kdevelop.pcs
+++ b/osirion.kdevelop.pcs
Binary files differ
diff --git a/osirion.kdevses b/osirion.kdevses
index 5dd7e63..7c59f5b 100644
--- a/osirion.kdevses
+++ b/osirion.kdevses
@@ -1,13 +1,19 @@
<?xml version = '1.0' encoding = 'UTF-8'?>
<!DOCTYPE KDevPrjSession>
<KDevPrjSession>
- <DocsAndViews NumberOfDocuments="2" >
+ <DocsAndViews NumberOfDocuments="4" >
<Doc0 NumberOfViews="1" URL="file:///home/ingar/projects/osirion/osirion-work/src/render/draw.cc" >
<View0 Encoding="" line="453" Type="Source" />
</Doc0>
<Doc1 NumberOfViews="1" URL="file:///home/ingar/projects/osirion/osirion-work/src/game/game.h" >
<View0 Encoding="" line="32" Type="Source" />
</Doc1>
+ <Doc2 NumberOfViews="1" URL="file:///home/ingar/projects/osirion/osirion-work/src/core/model.cc" >
+ <View0 Encoding="" line="630" Type="Source" />
+ </Doc2>
+ <Doc3 NumberOfViews="1" URL="file:///home/ingar/projects/osirion/osirion-work/src/render/sphere.cc" >
+ <View0 Encoding="" line="82" Type="Source" />
+ </Doc3>
</DocsAndViews>
<pluginList>
<kdevdebugger>
diff --git a/src/client/console.cc b/src/client/console.cc
index fc53b09..67a6ac9 100644
--- a/src/client/console.cc
+++ b/src/client/console.cc
@@ -194,7 +194,7 @@ void flush()
// save notification
notify_text[notify_pos] = line;
- notify_time[notify_pos] = sys::time();
+ notify_time[notify_pos] = core::application()->time();
notify_pos = (notify_pos+1) % MAXNOTIFYLINES;
// print to stdout
diff --git a/src/client/view.cc b/src/client/view.cc
index 5d14992..15b8606 100644
--- a/src/client/view.cc
+++ b/src/client/view.cc
@@ -146,10 +146,12 @@ void draw_status()
// print stats if desired
if (render::r_drawstats && render::r_drawstats->value()) {
std::stringstream stats;
- stats << "fps " << std::setw(6) << fps << "\n";
- stats << "tris " << std::setw(6) << render::Stats::tris << "\n";
- stats << "spheres " << std::setw(4) << render::Stats::spheres << "\n";
- draw_text(video::width-CHARWIDTH*13, CHARHEIGHT*3, stats);
+ stats << "fps " << std::setw(6) << fps << "\n";
+ if (core::application()->connected()) {
+ stats << "tris " << std::setw(6) << render::Stats::tris << "\n";
+ stats << "spheres " << std::setw(3) << render::Stats::spheres << "\n";
+ }
+ draw_text(video::width-CHARWIDTH*12, CHARHEIGHT*2, stats);
}
// print the version number in the upper right corner
@@ -161,10 +163,9 @@ void draw_status()
// draw notifications
gl::color(1.0f, 1.0f, 1.0f, 1.0f);
size_t n = console::notify_pos % MAXNOTIFYLINES;
- float now = sys::time();
int h = 4 + CHARHEIGHT;
for (size_t l = 0; l < MAXNOTIFYLINES; l++) {
- if (console::notify_text[n].size() > 2 && console::notify_time[n] + 4 > now) {
+ if (console::notify_text[n].size() > 2 && console::notify_time[n] + 4 > core::application()->time()) {
if (console::notify_text[n][0] == '?')
gl::color(0.7f,0.7f,0.7f, 1.0f);
else if (console::notify_text[n][0] == '*')
diff --git a/src/core/application.cc b/src/core/application.cc
index 5394b92..efa7bca 100644
--- a/src/core/application.cc
+++ b/src/core/application.cc
@@ -229,12 +229,9 @@ void Application::connect(std::string const &host)
if (host.size()) {
application_game = new GameConnection(host);
- if (application_game->running()) {
- con_print << "Connected to '" << host << "'\n";
- } else {
+ if (!application_game->running()) {
delete application_game;
application_game = 0;
- con_warn << "Could not connect to '" << host << "'!\n";
}
} else {
application_game = new GameServer();
diff --git a/src/core/gameconnection.cc b/src/core/gameconnection.cc
index 634a6ec..923d9a3 100644
--- a/src/core/gameconnection.cc
+++ b/src/core/gameconnection.cc
@@ -124,6 +124,8 @@ void GameConnection::frame(float seconds)
}
if (localplayer()->dirty()) {
+ localplayer()->update_info();
+
std::ostringstream osstream;
osstream << "pif ";
localplayer()->serialize_client_update(osstream);
diff --git a/src/core/gameinterface.cc b/src/core/gameinterface.cc
index 9f4dd29..a739eb2 100644
--- a/src/core/gameinterface.cc
+++ b/src/core/gameinterface.cc
@@ -42,23 +42,14 @@ GameInterface::GameInterface()
{
clear();
- if (Cvar::sv_dedicated->value())
+ game_localplayer.clear();
+ if (Cvar::sv_dedicated->value()) {
game_localplayer.player_name.assign("Console");
- else {
- game_localplayer.clear();
- Cvar *cl_name = Cvar::find("cl_name");
- if (cl_name) {
- game_localplayer.player_name = cl_name->str();
- }
-
- Cvar *cl_color = Cvar::find("cl_color");
- math::Color color(1.0, 1.0, 1.0, 1.0);
- if (cl_color && cl_color->value()) {
- std::istringstream is(cl_color->str());
- is >> color;
- }
- game_localplayer.player_color = color;
+ } else {
+ game_localplayer.player_name.assign("Player");
+ game_localplayer.update_info();
}
+
core::Func::add("list_model", (core::FuncPtr) func_list_model);
}
diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc
index 211bb96..1aa57f0 100644
--- a/src/core/gameserver.cc
+++ b/src/core/gameserver.cc
@@ -252,6 +252,9 @@ void GameServer::frame(float seconds)
}
}
+ if (localplayer()->dirty())
+ localplayer()->update_info();
+
// run a time frame on each entity
std::map<unsigned int, Entity *>::iterator it;
for (it=Entity::registry.begin(); it != Entity::registry.end(); it++) {
diff --git a/src/core/net.h b/src/core/net.h
index dd81580..150bbc1 100644
--- a/src/core/net.h
+++ b/src/core/net.h
@@ -20,6 +20,10 @@ const unsigned int MAXPENDINGCONNECTIONS = 32;
/// default network port
const unsigned int DEFAULTPORT = 8042;
+
+/// network timeout in seconds
+const float NETTIMEOUT = 15;
+
}
#include "core/netserver.h"
diff --git a/src/core/netclient.cc b/src/core/netclient.cc
index c7186f5..c910e26 100644
--- a/src/core/netclient.cc
+++ b/src/core/netclient.cc
@@ -9,6 +9,7 @@
#include "sys/sys.h"
#include "core/net.h"
+#include "core/application.h"
namespace core
{
@@ -38,6 +39,9 @@ NetClient::NetClient(std::string host, int port) :
sendq.clear();
messageblock.clear();
+ client_keepalive = application()->time();
+ client_timeout = application()->time();
+
client_error = false;
}
@@ -85,12 +89,15 @@ void NetClient::receive(char *data)
std::string datablock;
datablock.assign(data);
+ if (!datablock.size())
+ return;
+
while(datablock.size() > 0 ) {
// scan the datablock for enters
if (datablock[0] == '\n' || datablock[0] == '\r') {
// TODO detect "begin binary block" message for zlib compression
if (messageblock.size() > 0 ) {
- recvq.push_back(messageblock);
+ recvq.push_back(messageblock);
messageblock.clear();
}
} else {
@@ -103,6 +110,8 @@ void NetClient::receive(char *data)
}
datablock.erase(0,1);
}
+
+ client_timeout = application()->time();
}
void NetClient::send(std::string const &msg)
@@ -112,16 +121,23 @@ void NetClient::send(std::string const &msg)
void NetClient::transmit(int serverfd)
{
- if (sendq.size() >= BLOCKSIZE) {
- con_warn << "Outgoing message exceeds " << BLOCKSIZE << " bytes!\n";
- sendq.clear();
- return;
+
+ if (!sendq.size()) {
+ if (client_keepalive + NETTIMEOUT/2 < application()->time()) {
+ sendq.assign("ping\n");
+ } else {
+ return;
+ }
+ } else if (sendq.size() >= FRAMESIZE) {
+ con_warn << "Outgoing message exceeds " << FRAMESIZE << " bytes!\n";
+ //sendq.clear();
+ //return;
}
ssize_t bytes_sent = 0;
while (sendq.size() && !error()) {
- bytes_sent = sendto(serverfd, sendq.c_str(), sendq.size(), 0,
+ bytes_sent = ::sendto(serverfd, sendq.c_str(), sendq.size(), 0,
(struct sockaddr *)&client_addr, sizeof(client_addr));
if (bytes_sent < 0) {
@@ -132,6 +148,8 @@ void NetClient::transmit(int serverfd)
sendq.erase(0, bytes_sent);
}
sendq.clear();
+
+ client_keepalive = application()->time();
}
}
diff --git a/src/core/netclient.h b/src/core/netclient.h
index 1a7c716..49f509c 100644
--- a/src/core/netclient.h
+++ b/src/core/netclient.h
@@ -66,6 +66,9 @@ public:
inline State state() const { return client_state; }
State client_state;
+
+ float client_timeout;
+ float client_keepalive;
private:
struct sockaddr_in client_addr;
diff --git a/src/core/netconnection.cc b/src/core/netconnection.cc
index e3b4c69..b640595 100644
--- a/src/core/netconnection.cc
+++ b/src/core/netconnection.cc
@@ -17,7 +17,8 @@ namespace core
NetConnection::NetConnection()
{
- timeout = core::application()->time();
+ connection_timeout = core::application()->time();
+ connection_state = Connecting;
}
NetConnection::~NetConnection()
@@ -34,6 +35,7 @@ void NetConnection::connect(std::string const &to_host, int to_port)
{
connection_error = false;
connection_fd = -1;
+ connection_state = Connecting;
if (valid())
return;
@@ -47,8 +49,6 @@ void NetConnection::connect(std::string const &to_host, int to_port)
return;
}
- con_print << "Connecting to " << inet_ntoa(*((struct in_addr *)serverhostent->h_addr)) << ":" << to_port << "..." << std::endl;
-
// Get a socket file descriptor
connection_fd = socket(PF_INET, SOCK_DGRAM, 0);
if (connection_fd == -1) {
@@ -69,7 +69,6 @@ void NetConnection::connect(std::string const &to_host, int to_port)
return;
}
-
connection_host = to_host;
connection_port = to_port;
connection_error = false;
@@ -77,8 +76,12 @@ void NetConnection::connect(std::string const &to_host, int to_port)
FD_ZERO(&clientset);
FD_SET(fd(), &clientset);
- timeout = core::application()->time();
+ connection_timeout = application()->time();
+ connection_keepalive = application()->time();
+
game()->localplayer()->player_dirty = true;
+
+ con_print << "Connecting to " << inet_ntoa(*((struct in_addr *)serverhostent->h_addr)) << ":" << to_port << "..." << std::endl;
}
void NetConnection::disconnect()
@@ -96,6 +99,7 @@ void NetConnection::disconnect()
connection_error = false;
connection_host.clear();
connection_port = 0;
+ connection_state = Connecting;
}
bool NetConnection::has_messages() const
@@ -124,7 +128,7 @@ void NetConnection::receive()
memset(recvbuf, '\0', BLOCKSIZE);
bytes_received = ::recv(connection_fd, recvbuf, BLOCKSIZE-1, 0);
- timeout = core::application()->time();
+ connection_timeout = core::application()->time();
if (bytes_received == 0) {
con_print << "Disconnected.";
@@ -168,12 +172,10 @@ void NetConnection::frame(float seconds)
int nb = select(fd()+1, &readset, NULL, NULL, &timeout);
if (nb == 0) {
- /*
- if (timout + TIMEOUT < core::application()->time()) {
- con_error << "Connection time out\n";
+ if (connection_timeout + NETTIMEOUT < core::application()->time()) {
+ con_error << "Connection timeout!\n";
abort();
}
- */
return;
}
if (nb == -1) {
@@ -213,8 +215,14 @@ void NetConnection::transmit()
if (error() || invalid())
return;
-
- if (sendq.size() > FRAMESIZE) {
+
+ if (!sendq.size()) {
+ if (connection_keepalive + NETTIMEOUT /2 < application()->time()) {
+ sendq.assign("ping\n");
+ } else {
+ return;
+ }
+ } else if (sendq.size() > FRAMESIZE) {
con_warn << "Outgoing message exceeds " << FRAMESIZE << " bytes!\n";
//sendq.clear();
//return;
@@ -234,14 +242,16 @@ void NetConnection::transmit()
// assert (bytes_sent <= sendbuf.size());
sendq.erase(0, bytes_sent);
}
-
- sendq.clear();
+
+ connection_keepalive = application()->time();
}
// parse incoming client messages
/**
* The following incoming messages are parsed;
*
+ * connect
+ * disconnect
* msg info <text>
* msg public <name> <text>
* die
@@ -271,6 +281,19 @@ void NetConnection::parse_incoming_message(const std::string & message)
}
}
+ } else if (command == "connect") {
+
+ connection_state = Connected;
+ con_print << "Connected." << std::endl;
+ return;
+
+ } else if (command == "disconnect") {
+
+ con_error << "Server disconnected!" << std::endl;
+ abort();
+
+ } else if (command == "ping") {
+
} else if (command == "die") {
unsigned int id;
msgstream >> id;
@@ -312,9 +335,9 @@ void NetConnection::parse_incoming_message(const std::string & message)
} else
entity->recieve_server_update(msgstream);
}
- return;
} else if (command == "pif") {
+
connection()->localplayer()->recieve_server_update(msgstream);
}
diff --git a/src/core/netconnection.h b/src/core/netconnection.h
index dca85c7..08536de 100644
--- a/src/core/netconnection.h
+++ b/src/core/netconnection.h
@@ -67,6 +67,12 @@ public:
inline bool connected() const { return ((connection_fd != -1) && !connection_error); }
+ enum State {Connecting=0, Connected=1};
+
+ inline State state() const { return connection_state; }
+
+ State connection_state;
+
protected:
/// receive incoming data and store messages
void receive();
@@ -86,14 +92,14 @@ private:
std::string sendq;
fd_set clientset;
+ float connection_timeout;
+ float connection_keepalive;
int connection_fd;
bool connection_error;
std::string connection_host;
int connection_port;
struct sockaddr_in server_addr;
char recvbuf[BLOCKSIZE];
-
- float timeout;
};
}
diff --git a/src/core/netserver.cc b/src/core/netserver.cc
index 16beee0..c9870c5 100644
--- a/src/core/netserver.cc
+++ b/src/core/netserver.cc
@@ -86,6 +86,8 @@ NetServer::~NetServer()
{
con_print << "Shutting down network server..." << std::endl;
+ std::string netmsg("disconnect\n");
+
// delete all clients
std::list<NetClient *>:: iterator it;
for (it = clients.begin(); it != clients.end(); it++) {
@@ -94,6 +96,9 @@ NetServer::~NetServer()
if ((*it)->state() == NetClient::Connected)
server()->player_disconnect((*it)->player());
+ (*it)->send(netmsg);
+ (*it)->transmit(fd());
+
delete (*it);
}
clients.clear();
@@ -108,6 +113,24 @@ void NetServer::reap()
for (std::list<NetClient *>:: iterator it = clients.begin(); it != clients.end(); it++) {
NetClient *client = *it;
+ if (client->client_timeout + NETTIMEOUT < application()->time()) {
+ // client timed out, send a disconnect
+ std::string netmsg("disconnect\n");
+ (*it)->send(netmsg);
+ (*it)->transmit(fd());
+ (*it)->abort();
+
+ // print a message
+ std::string message(client->player()->name());
+ message.append(" timed out.");
+
+ if (client->state() == NetClient::Connected) {
+ server()->broadcast(message, client->player());
+ } else {
+ con_print << message << std::endl;
+ }
+ }
+
if (client->error()) {
// notify the game server
@@ -234,15 +257,15 @@ NetClient * NetServer::client_connect(std::string const host, int const port)
clients.push_back(client);
+ // send welcome message
std::ostringstream netmsg;
netmsg.str("");
netmsg << "msg info Receiving data from remote server...\n";
client->send(netmsg.str());
- transmit();
+ client->transmit(fd());
// send entities
std::map<unsigned int, Entity *>::iterator it;
-
for (it=Entity::registry.begin(); it != Entity::registry.end(); it++) {
netmsg.str("");
switch ((*it).second->type()) {
@@ -260,8 +283,7 @@ NetClient * NetServer::client_connect(std::string const host, int const port)
break;
}
}
-
- transmit();
+ client->transmit(fd());
client->player()->player_dirty = false;
@@ -303,6 +325,7 @@ NetClient *NetServer::find_client(Player const *player)
* cmd <game command>
* cup
* pif
+ * ping
* say <text>
*
*/
@@ -331,13 +354,23 @@ void NetServer::parse_incoming_message(NetClient *client, const std::string & me
if (client->state() == NetClient::Connecting) {
client->client_state = NetClient::Connected;
server()->player_connect(client->player());
+
+ std::string netmsg("connect\n");
+ client->send(netmsg);
+
} else if ((client->state() == NetClient::Connected) && (client->player()->name() != oldname)) {
- oldname.append(" renamed to ");
- oldname.append(client->player()->name());
- server()->broadcast(oldname);
+
+ std::string netmsg(oldname);
+ netmsg.append(" renamed to ");
+ netmsg.append(client->player()->name());
+ server()->broadcast(netmsg);
}
}
+ if (command == "ping") {
+ return;
+ }
+
if (client->state() != NetClient::Connected)
return;
diff --git a/src/core/player.cc b/src/core/player.cc
index b89da99..71ac8de 100644
--- a/src/core/player.cc
+++ b/src/core/player.cc
@@ -44,21 +44,25 @@ void Player::clear_assets()
player_control = 0;
}
-void Player::serialize_client_update(std::ostream & os)
+void Player::update_info()
{
Cvar *cl_name = Cvar::find("cl_name");
if (cl_name) {
- player_name = cl_name->str();
+ if (cl_name->str().size())
+ player_name = cl_name->str();
}
-
+
Cvar *cl_color = Cvar::find("cl_color");
math::Color color(1.0, 1.0, 1.0, 1.0);
if (cl_color) {
std::istringstream is(cl_color->str());
- is >> color;
- player_color = color;
+ if (is >> color)
+ player_color = color;
}
-
+}
+
+void Player::serialize_client_update(std::ostream & os)
+{
os << " " << player_color << " \"" << player_name << "\"";
}
diff --git a/src/core/player.h b/src/core/player.h
index 59b18c1..08abac2 100644
--- a/src/core/player.h
+++ b/src/core/player.h
@@ -74,6 +74,9 @@ public:
/// remove an asset
void remove_asset(unsigned int id);
+ /// update player info from client variables
+ void update_info();
+
/* -- should actually not be public --*/
// dirty state