Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorStijn Buys <ingar@osirion.org>2008-03-21 19:25:11 +0000
committerStijn Buys <ingar@osirion.org>2008-03-21 19:25:11 +0000
commit2314c27dd650dc02c0b5bdd3bef75818393a9ab5 (patch)
tree231815c866a1330338d976480284250e99207554 /src/core
parent7e99fac4552b402034e5fc3e833cbe8c274f95ce (diff)
switched to UDP networking
Diffstat (limited to 'src/core')
-rw-r--r--src/core/Makefile.am6
-rw-r--r--src/core/application.cc17
-rw-r--r--src/core/core.h7
-rw-r--r--src/core/cvar.cc2
-rw-r--r--src/core/cvar.h1
-rw-r--r--src/core/entity.cc4
-rw-r--r--src/core/gameconnection.cc6
-rw-r--r--src/core/gameinterface.cc5
-rw-r--r--src/core/gameserver.cc29
-rw-r--r--src/core/gameserver.h3
-rw-r--r--src/core/net.h30
-rw-r--r--src/core/netclient.cc87
-rw-r--r--src/core/netclient.h48
-rw-r--r--src/core/netconnection.cc167
-rw-r--r--src/core/netconnection.h38
-rw-r--r--src/core/netserver.cc331
-rw-r--r--src/core/netserver.h48
-rw-r--r--src/core/player.cc3
18 files changed, 596 insertions, 236 deletions
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 6f78e6a..a73a8a7 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -5,10 +5,10 @@ libcore_la_SOURCES = application.cc commandbuffer.cc core.cc cvar.cc entity.cc \
func.cc gameconnection.cc gameinterface.cc gameserver.cc model.cc module.cc \
netclient.cc netconnection.cc netserver.cc player.cc
libcore_la_LDFLAGS = -avoid-version -no-undefined
-libcore_la_LIBADD = $(top_builddir)/src/math/libmath.la \
- $(top_builddir)/src/filesystem/libfilesystem.la $(top_builddir)/src/sys/libsys.la $(top_builddir)/src/net/libnet.la
+libcore_la_LIBADD = $(top_builddir)/src/filesystem/libfilesystem.la \
+ $(top_builddir)/src/math/libmath.la $(top_builddir)/src/sys/libsys.la
noinst_LTLIBRARIES = libcore.la
noinst_HEADERS = application.h commandbuffer.h core.h cvar.h entity.h func.h \
- gameconnection.h gameinterface.h gameserver.h module.h netconnection.h player.h
+ gameconnection.h gameinterface.h gameserver.h module.h net.h netconnection.h player.h
diff --git a/src/core/application.cc b/src/core/application.cc
index 358c655..5394b92 100644
--- a/src/core/application.cc
+++ b/src/core/application.cc
@@ -165,8 +165,9 @@ void Application::init()
Cvar::sv_framerate = Cvar::get("sv_framerate", "25");
// network settings
- Cvar::net_host = Cvar::get("net_host", "0.0.0.0");
- Cvar::net_port = Cvar::get("net_port", "8042");
+ Cvar::net_host = Cvar::get("net_host", "0.0.0.0", Cvar::Archive);
+ Cvar::net_port = Cvar::get("net_port", "8042", Cvar::Archive);
+ Cvar::net_maxclients = Cvar::get("net_maxclients", "16", Cvar::Archive);
// register our engine functions
Func::add("print", func_print);
@@ -282,7 +283,10 @@ void Application::frame(float seconds)
void Application::save_config()
{
std::string filename(filesystem::writedir);
- filename.append("config.txt");
+ if (!Cvar::sv_dedicated->value())
+ filename.append("client.cfg");
+ else
+ filename.append("server.cfg");
std::ofstream ofs(filename.c_str());
if (!ofs.is_open()) {
@@ -294,7 +298,7 @@ void Application::save_config()
for (it = Cvar::registry.begin(); it != Cvar::registry.end(); it++) {
if (((*it).second->flags() & Cvar::Archive) == Cvar::Archive)
- ofs << "set " << (*it).first << " " << (*it).second->str() << std::endl;
+ ofs << "set " << (*it).first << " " << (*it).second->str() << std::endl;
}
ofs.close();
}
@@ -302,7 +306,10 @@ void Application::save_config()
void Application::load_config()
{
std::string filename(filesystem::writedir);
- filename.append("config.txt");
+ if (!Cvar::sv_dedicated->value())
+ filename.append("client.cfg");
+ else
+ filename.append("server.cfg");
std::ifstream ifs(filename.c_str(), std::ifstream::in);
if (!ifs.is_open()) {
diff --git a/src/core/core.h b/src/core/core.h
index ddf884f..a3e13e4 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -16,19 +16,16 @@
#include "core/func.h"
#include "core/gameinterface.h"
#include "core/module.h"
-#include "core/netserver.h"
-#include "core/netclient.h"
-#include "core/netconnection.h"
#include "core/player.h"
/// core contains the basic functionality of the engine
namespace core
{
-// name of the engine core
+/// name of the engine core
const std::string & name();
-// version of the engine core
+/// version of the engine core
const std::string & version();
}
diff --git a/src/core/cvar.cc b/src/core/cvar.cc
index 363ebb4..e95f61c 100644
--- a/src/core/cvar.cc
+++ b/src/core/cvar.cc
@@ -20,8 +20,10 @@ namespace core
Cvar *Cvar::sv_dedicated = 0;
Cvar *Cvar::sv_private = 0;
Cvar *Cvar::sv_framerate = 0;
+
Cvar *Cvar::net_host = 0;
Cvar *Cvar::net_port = 0;
+Cvar *Cvar::net_maxclients = 0;
std::map<std::string, Cvar*> Cvar::registry;
diff --git a/src/core/cvar.h b/src/core/cvar.h
index f43e532..21f2601 100644
--- a/src/core/cvar.h
+++ b/src/core/cvar.h
@@ -105,6 +105,7 @@ public:
static Cvar *sv_framerate; // server framerate
static Cvar *net_host; // network server ip (default binds to all interfaces)
static Cvar *net_port; // network port
+ static Cvar *net_maxclients; // maximum number of connected clients
private:
std::string cvar_name;
diff --git a/src/core/entity.cc b/src/core/entity.cc
index d64ae61..fd28a1c 100644
--- a/src/core/entity.cc
+++ b/src/core/entity.cc
@@ -316,7 +316,7 @@ void EntityControlable::set_thrust(float thrust)
if ((flags() & Static) == Static)
return;
- if (!(thrust == target_thrust)) {
+ if (thrust != target_thrust) {
target_thrust = thrust;
entity_dirty = true;
}
@@ -327,7 +327,7 @@ void EntityControlable::set_direction(float direction)
if ((flags() & Static) == Static)
return;
- if (!(target_direction == direction)) {
+ if (target_direction != direction) {
target_direction = direction;
entity_dirty = true;
}
diff --git a/src/core/gameconnection.cc b/src/core/gameconnection.cc
index b307fee..634a6ec 100644
--- a/src/core/gameconnection.cc
+++ b/src/core/gameconnection.cc
@@ -8,9 +8,9 @@
#include <sstream>
#include "sys/sys.h"
-#include "net/net.h"
#include "core/cvar.h"
#include "core/gameconnection.h"
+#include "core/net.h"
namespace core
{
@@ -23,7 +23,7 @@ GameConnection::GameConnection(std::string const &connectionstr)
connection_network = 0;
connection_running = false;
- unsigned int port = net::DEFAULTPORT;
+ unsigned int port = DEFAULTPORT;
std::string host(connectionstr);
size_t found = host.find(':');
@@ -129,11 +129,11 @@ void GameConnection::frame(float seconds)
localplayer()->serialize_client_update(osstream);
osstream << '\n';
connection_network->send(osstream.str());
+ localplayer()->player_dirty = false;
}
connection_network->transmit();
connection_frametime += f;
-
}
}
diff --git a/src/core/gameinterface.cc b/src/core/gameinterface.cc
index 69126e7..9f4dd29 100644
--- a/src/core/gameinterface.cc
+++ b/src/core/gameinterface.cc
@@ -45,6 +45,7 @@ GameInterface::GameInterface()
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();
@@ -52,7 +53,7 @@ GameInterface::GameInterface()
Cvar *cl_color = Cvar::find("cl_color");
math::Color color(1.0, 1.0, 1.0, 1.0);
- if (cl_color) {
+ if (cl_color && cl_color->value()) {
std::istringstream is(cl_color->str());
is >> color;
}
@@ -65,6 +66,8 @@ GameInterface::~GameInterface()
{
core::Func::remove("list_model");
+ game_localplayer.clear();
+
clear();
}
diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc
index 985fac4..add0ca9 100644
--- a/src/core/gameserver.cc
+++ b/src/core/gameserver.cc
@@ -58,8 +58,9 @@ GameServer::GameServer() : GameInterface()
Func::add("say", (GameFuncPtr) func_say);
- if (!Cvar::sv_dedicated->value())
+ if (!Cvar::sv_dedicated->value()) {
player_connect(localplayer());
+ }
server_running = true;
}
@@ -113,7 +114,7 @@ void GameServer::say(Player *player, std::string const &message)
}
}
-void GameServer::broadcast(std::string const & message, int ignoreplayer)
+void GameServer::broadcast(std::string const & message, Player *ignore_player)
{
// send to console
con_print << message << "\n";
@@ -123,7 +124,7 @@ void GameServer::broadcast(std::string const & message, int ignoreplayer)
std::string netmessage("msg info ");
netmessage.append(message);
netmessage += '\n';
- server_network->broadcast(netmessage, ignoreplayer);
+ server_network->broadcast(netmessage, ignore_player);
}
}
@@ -179,7 +180,7 @@ void GameServer::player_connect(Player *player)
{
std::string message(player->name());
message.append(" connects.");
- broadcast(message, player->id());
+ broadcast(message, player);
// notify the game module
server_module->player_connect(player);
@@ -189,7 +190,7 @@ void GameServer::player_disconnect(Player *player)
{
std::string message(player->name());
message.append(" disconnects.");
- broadcast(message, player->id());
+ broadcast(message, player);
// notify the game module
server_module->player_disconnect(player);
@@ -201,8 +202,9 @@ void GameServer::frame(float seconds)
return;
// process incoming network messages
- if (server_network != 0 ) {
- server_network->frame(seconds);
+ if (server_network) {
+ server_network->receive();
+
if (server_network->error()) {
abort();
return;
@@ -230,6 +232,10 @@ void GameServer::frame(float seconds)
// send updates
if (server_network) {
+ // transmit buffered sends
+ server_network->transmit();
+
+ // TODO - start server frame
std::map<unsigned int, Entity *>::iterator it;
for (it=Entity::registry.begin(); it != Entity::registry.end(); it++) {
Entity *entity = (*it).second;
@@ -261,7 +267,7 @@ void GameServer::frame(float seconds)
// update player info
for (std::list<NetClient *>::iterator it = server_network->clients.begin(); it != server_network->clients.end(); it++) {
NetClient *client = *it;
- if (client->player()->dirty()) {
+ if (client->player()->dirty() && (client->state() == NetClient::Connected)) {
// send player data
std::ostringstream netmsg;
netmsg.str("");
@@ -272,12 +278,11 @@ void GameServer::frame(float seconds)
client->player()->player_dirty = false;
}
}
+ // TODO - end server frame
// transmit buffered sends
- for (std::list<NetClient *>::iterator it = server_network->clients.begin(); it != server_network->clients.end(); it++) {
- (*it)->transmit();
- }
-
+ server_network->transmit();
+
} else {
// local update stub
diff --git a/src/core/gameserver.h b/src/core/gameserver.h
index 17d581c..fd2021e 100644
--- a/src/core/gameserver.h
+++ b/src/core/gameserver.h
@@ -47,7 +47,7 @@ public:
void say(Player *player, std::string const &args);
/// broadcast a message to all players
- void broadcast(std::string const & message, int ignoreplayer = -1);
+ void broadcast(std::string const & message, Player *ignore_player = 0);
/// send a message to a single player
void send(Player *player, std::string message);
@@ -69,7 +69,6 @@ private:
Module *server_module;
static GameServer *server_instance;
NetServer *server_network;
-
};
inline GameServer *server() { return GameServer::instance(); }
diff --git a/src/core/net.h b/src/core/net.h
new file mode 100644
index 0000000..dd81580
--- /dev/null
+++ b/src/core/net.h
@@ -0,0 +1,30 @@
+/*
+ core/net.h
+ This file is part of the Osirion project and is distributed under
+ the terms of the GNU General Public License version 2
+*/
+
+#ifndef __INCLUDED_CORE_NET_H__
+#define __INCLUDED_CORE_NET_H__
+
+/// this namespace contains the network subsystem
+namespace core
+{
+
+/// maximum lenght of a (compressed) network message block
+const unsigned int FRAMESIZE = 1152;
+const unsigned int BLOCKSIZE = 8192;
+
+/// maximum number of pending client connections, hard limit
+const unsigned int MAXPENDINGCONNECTIONS = 32;
+
+/// default network port
+const unsigned int DEFAULTPORT = 8042;
+}
+
+#include "core/netserver.h"
+#include "core/netclient.h"
+#include "core/netconnection.h"
+
+#endif // __INCLUDED_CORE_NET_H__
+
diff --git a/src/core/netclient.cc b/src/core/netclient.cc
index 0f56bb9..32e0f4b 100644
--- a/src/core/netclient.cc
+++ b/src/core/netclient.cc
@@ -8,31 +8,61 @@
#include <sstream>
#include "sys/sys.h"
-#include "net/net.h"
-#include "core/netclient.h"
+#include "core/net.h"
namespace core
{
-NetClient::NetClient(int clientfd, std::string host, int port) :
- net::TCPClient(clientfd),
+NetClient::NetClient(std::string host, int port) :
client_host(host)
{
- std::ostringstream osstream;
- //osstream << "host << ":" << port;
- osstream << "Player" << clientfd;
- client_player.player_name = osstream.str();
- client_player.player_id = (unsigned int) clientfd;
+ client_error = true;
+ client_state = Connecting;
+
+ con_print << host << ":" << port << " connects." << std::endl;
+ // Get a socket file descriptor
+ client_fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (client_fd == -1) {
+ con_warn << "Network client socket() failed!" << std::endl;
+ abort();
+ return;
+ }
+
client_host = host;
client_port = port;
- sendq.clear();
+ client_addr.sin_family = AF_INET;
+ client_addr.sin_port = htons(port);
+ client_addr.sin_addr.s_addr = inet_addr(host.c_str());
+ if (client_addr.sin_addr.s_addr == INADDR_NONE) {
+ con_warn << "Network invalid client address " << host << "!" << std::endl;
+ abort();
+ return;
+ }
+ memset(client_addr.sin_zero, '\0', sizeof(client_addr.sin_zero));
+
+ std::ostringstream osstream;
+ client_player.player_id = client_fd;
+
+ sendq.erase();
messageblock.clear();
+
+ client_error = false;
}
NetClient::~NetClient()
{
+ con_print << host() << ":" << port() << " disconnects." << std::endl;
+
+ if (client_fd) {
+ ::close(client_fd);
+ }
+}
+
+void NetClient::abort()
+{
+ client_error = true;
}
std::string NetClient::host() const
@@ -64,10 +94,10 @@ void NetClient::retreive(std::string & message) {
}
// receive data and decode it into lines
-void NetClient::receive()
+void NetClient::receive(char *data)
{
std::string datablock;
- net::TCPClient::receive(datablock);
+ datablock.assign(data);
while(datablock.size() > 0 ) {
// scan the datablock for enters
@@ -75,19 +105,18 @@ void NetClient::receive()
// TODO detect "begin binary block" message for zlib compression
if (messageblock.size() > 0 ) {
recvq.push_back(messageblock);
- messageblock.clear();
+ messageblock.erase();
}
} else {
- if (messageblock.size() < net::FRAMESIZE) {
+ if (messageblock.size() < FRAMESIZE) {
messageblock.append(datablock.substr(0,1));
} else {
- con_warn << "NetClient " << fd() << ": message block overflow" << std::endl;
- messageblock.clear();
+ con_warn << "Incoming message exceeds " << FRAMESIZE << " bytes!\n";
+ messageblock.erase();
}
}
datablock.erase(0,1);
}
- datablock.clear();
}
void NetClient::send(std::string const &msg)
@@ -97,14 +126,26 @@ void NetClient::send(std::string const &msg)
void NetClient::transmit()
{
- while (sendq.size() && valid() && !error()) {
- TCPClient::send(sendq.substr(0, net::FRAMESIZE-1));
- if (sendq.size() < net::FRAMESIZE) {
- sendq.clear();
- } else {
- sendq.erase(0, net::FRAMESIZE-1);
+ if (sendq.size() >= BLOCKSIZE) {
+ con_warn << "Outgoing message exceeds " << BLOCKSIZE << " bytes!\n";
+ sendq.clear();
+ return;
+ }
+
+ ssize_t bytes_sent = 0;
+
+ while (sendq.size() && !error()) {
+ bytes_sent = sendto(client_fd, sendq.c_str(), sendq.size(), 0,
+ (struct sockaddr *)&client_addr, sizeof(client_addr));
+
+ if (bytes_sent < 0) {
+ abort();
+ return;
}
+
+ sendq.erase(0, bytes_sent);
}
+ sendq.clear();
}
}
diff --git a/src/core/netclient.h b/src/core/netclient.h
index 23a2787..2fde530 100644
--- a/src/core/netclient.h
+++ b/src/core/netclient.h
@@ -7,21 +7,30 @@
#ifndef __INCLUDED_CORE_NETCLIENT_H__
#define __INCLUDED_CORE_NETCLIENT_H__
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
#include <string>
#include <deque>
#include <map>
-#include "net/tcpclient.h"
#include "core/player.h"
namespace core
{
/// queues incoming client messages
-class NetClient : public net::TCPClient
+class NetClient
{
public:
- NetClient(int clientfd, std::string host, int port);
+ NetClient(std::string host, int port);
~NetClient();
/// the remote hostname the client is connected to
@@ -33,26 +42,41 @@ public:
/// the player info associated with this client
Player *player();
- /// return true if there are incoming messages
+ /// bufer incoming data
+ void receive(char *data);
+
+ /// buffer outgoing data
+ void send(std::string const &msg);
+
+ /// return true if there is buffered incoming data
bool has_messages() const;
- /// receive an incoming message
+ /// retreive buffered incoming data
void retreive(std::string & message);
- /// receive incoming data and store messages
- void receive();
+ /// transmit buffered outgoing data
+ void transmit();
+
+ inline bool error() const { return client_error; }
- /// buffer outgoing data
- void send(std::string const &msg);
+ inline int fd() const { return client_fd; }
- /// send bufered outgoing data
- void transmit();
+ void abort();
+
+ enum State {Connecting=0, Connected=1};
+
+ inline State state() const { return client_state; }
+ State client_state;
+
private:
+ struct sockaddr_in client_addr;
std::string client_host;
int client_port;
Player client_player;
-
+ bool client_error;
+ int client_fd;
+
std::string messageblock;
std::deque<std::string> recvq;
std::string sendq;
diff --git a/src/core/netconnection.cc b/src/core/netconnection.cc
index 9790655..379df14 100644
--- a/src/core/netconnection.cc
+++ b/src/core/netconnection.cc
@@ -7,7 +7,6 @@
#include <sstream>
#include "sys/sys.h"
-#include "net/net.h"
#include "core/application.h"
#include "core/gameconnection.h"
#include "core/netconnection.h"
@@ -22,27 +21,86 @@ NetConnection::NetConnection()
NetConnection::~NetConnection()
{
+ disconnect();
+}
+
+void NetConnection::abort()
+{
+ connection_error= true;
}
void NetConnection::connect(std::string const &to_host, int to_port)
{
- TCPConnection::connect(to_host, to_port);
- if(connected()) {
- FD_ZERO(&clientset);
- FD_SET(fd(), &clientset);
+ connection_error = false;
+ connection_fd = -1;
+
+ if (valid())
+ return;
+
+ // resolve serverhostname
+ struct hostent *serverhostent;
+ serverhostent = gethostbyname(to_host.c_str());
+ if (!serverhostent) {
+ con_warn << "Could not resolve '" << to_host.c_str() << "'" << std::endl;
+ abort();
+ 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) {
+ //con_error << "Network socket() failed!" << std::endl;
+ abort();
+ return;
+ }
+
+ // make the connection
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(to_port);
+ // FIXME inet_addr can still fail
+ server_addr.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)serverhostent->h_addr)));
+ if (server_addr.sin_addr.s_addr == INADDR_NONE) {
+ con_error << "Network invalid address " << to_host << "!" << std::endl;
+ abort();
+ return;
+ }
+ memset(server_addr.sin_zero, '\0', sizeof server_addr.sin_zero);
+
+ /*
+ if (::connect(connection_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) != 0) {
+ //con_error << "Network connect() failed!" << std::endl;
+ abort();
+ return;
+ }
+ */
+
+ connection_host = to_host;
+ connection_port = to_port;
+ connection_error = false;
- std::ostringstream osstream;
- osstream << "pif ";
- game()->localplayer()->serialize_client_update(osstream);
- osstream << '\n';
- send(osstream.str());
+ FD_ZERO(&clientset);
+ FD_SET(fd(), &clientset);
+
+ game()->localplayer()->player_dirty = true;
}
void NetConnection::disconnect()
{
- TCPConnection::disconnect();
- FD_ZERO(&clientset);
+ if (connection_fd != -1) {
+ sendq.clear();
+ sendq.assign("disconnect\n");
+ transmit();
+
+ FD_ZERO(&clientset);
+ close(connection_fd);
+ }
+
+ connection_fd = -1;
+ connection_error = false;
+ connection_host.clear();
+ connection_port = 0;
}
bool NetConnection::has_messages() const
@@ -64,25 +122,41 @@ void NetConnection::retreive(std::string & message)
void NetConnection::receive()
{
// TODO: binary mode data transfer
- std::string datablock;
- TCPConnection::receive(datablock);
+ if (error() || invalid())
+ return;
+
+ ssize_t bytes_received;
+
+ memset(recvbuf, '\0', BLOCKSIZE);
+ bytes_received = ::recv(connection_fd, recvbuf, BLOCKSIZE-1, 0);
- if (error())
+ if (bytes_received == 0) {
+ con_print << "Disconnected.";
+ abort();
+ return;
+ } else if (bytes_received < 0) {
+ con_error << "Network receive() error!" << std::endl;
+ //perror("recv");
+ abort();
return;
- while (datablock.size() > 0) {
+ }
+
+ std::string datablock;
+ datablock.assign(recvbuf);
+
+ while (datablock.size()) {
// scan the datablock for enters
if (datablock[0] == '\n' || datablock[0] == '\r') {
- if (messageblock.size() > 0) {
+ if (messageblock.size() >= FRAMESIZE) {
+ con_warn << "Incoming message exceeds " << FRAMESIZE << " bytes!\n";
+ messageblock.clear();
+ } else if (messageblock.size()) {
recvq.push_back(messageblock);
+ //con_debug << "Incoming message '" << messageblock << "'" << std::endl;
messageblock.clear();
}
} else {
- if (messageblock.size() < net::FRAMESIZE) {
- messageblock.append(datablock.substr(0,1));
- } else {
- con_warn << "Network message exceeds " << net::FRAMESIZE << " bytes!" << std::endl;
- messageblock.clear();
- }
+ messageblock.append(datablock.substr(0,1));
}
datablock.erase(0,1);
}
@@ -97,22 +171,33 @@ void NetConnection::frame(float seconds)
fd_set readset = clientset;
int nb = select(fd()+1, &readset, NULL, NULL, &timeout);
- if (nb == 0)
+ if (nb == 0) {
return;
-
+ }
if (nb == -1) {
con_error << "Network error on select()" << std::endl;
//perror("select");
abort();
}
- if (FD_ISSET(this->fd(), &readset) && !error()) {
+ while (FD_ISSET(this->fd(), &readset) && !error()) {
receive();
+
while (has_messages()) {
std::string message;
retreive(message);
parse_incoming_message(message);
}
+
+ nb = select(fd()+1, &readset, NULL, NULL, &timeout);
+ if (nb == 0) {
+ return;
+ }
+ if (nb == -1) {
+ con_error << "Network error on select()" << std::endl;
+ //perror("select");
+ abort();
+ }
}
}
@@ -123,14 +208,32 @@ void NetConnection::send(std::string const &msg)
void NetConnection::transmit()
{
- while (sendq.size() && valid() && !error()) {
- TCPConnection::send(sendq.substr(0, net::FRAMESIZE-1));
- if (sendq.size() < net::FRAMESIZE) {
- sendq.clear();
- } else {
- sendq.erase(0, net::FRAMESIZE-1);
+
+ if (error() || invalid())
+ return;
+
+ if (sendq.size() > FRAMESIZE) {
+ con_warn << "Outgoing message exceeds " << FRAMESIZE << " bytes!\n";
+ //sendq.clear();
+ //return;
+ }
+
+ ssize_t bytes_sent = 0;
+
+ while (sendq.size()) {
+ bytes_sent = ::sendto(connection_fd, sendq.c_str(), sendq.size(), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
+ if (bytes_sent <= 0) {
+ con_error << "Network send() error!" << std::endl;
+ //perror("send");
+ abort();
+ return;
}
+
+ // assert (bytes_sent <= sendbuf.size());
+ sendq.erase(0, bytes_sent);
}
+
+ sendq.clear();
}
// parse incoming client messages
diff --git a/src/core/netconnection.h b/src/core/netconnection.h
index 7623e64..f378afb 100644
--- a/src/core/netconnection.h
+++ b/src/core/netconnection.h
@@ -7,19 +7,30 @@
#ifndef __INCLUDED_CORE_NETCONNECTION_H__
#define __INCLUDED_CORE_NETCONNECTION_H__
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
#include <sys/select.h>
+#include <netdb.h>
#include <string>
#include <deque>
#include <map>
-#include "net/tcpconnection.h"
+#include "core/net.h"
namespace core
{
/// a client to server connection
-class NetConnection : public net::TCPConnection
+class NetConnection
{
public:
NetConnection();
@@ -40,6 +51,22 @@ public:
/// send bufered outgoing data
void transmit();
+ void abort();
+
+ inline int fd() const { return connection_fd; }
+
+ inline std::string host() const { return connection_host; }
+
+ inline int port() const { return connection_port; }
+
+ inline bool valid() const { return (connection_fd != -1); }
+
+ inline bool invalid() const { return (connection_fd == -1); }
+
+ inline bool error() const { return connection_error; }
+
+ inline bool connected() const { return ((connection_fd != -1) && !connection_error); }
+
protected:
/// receive incoming data and store messages
void receive();
@@ -58,6 +85,13 @@ private:
std::deque<std::string> recvq;
std::string sendq;
fd_set clientset;
+
+ int connection_fd;
+ bool connection_error;
+ std::string connection_host;
+ int connection_port;
+ struct sockaddr_in server_addr;
+ char recvbuf[BLOCKSIZE];
};
}
diff --git a/src/core/netserver.cc b/src/core/netserver.cc
index 87f5320..16f042e 100644
--- a/src/core/netserver.cc
+++ b/src/core/netserver.cc
@@ -4,6 +4,16 @@
the terms of the GNU General Public License version 2
*/
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
#include <iostream>
#include <sstream>
@@ -18,15 +28,58 @@
namespace core
{
-NetServer::NetServer(std::string const host, unsigned int const port) :
- net::TCPServer(host, port)
+NetServer::NetServer(std::string const host, unsigned int const port)
{
- //con_print << "Initializing network server..." << std::endl;
- FD_ZERO(&serverset);
+ con_print << "Initializing network server..." << std::endl;
+
+ // initialize variables
+ netserver_fd = -1;
+ netserver_error = true;
+
+ // initialize socket
+ netserver_fd = ::socket(PF_INET, SOCK_DGRAM, 0);
+ if (netserver_fd == -1) {
+ con_error << "Network can't create socket!" << std::endl;
+ //perror("socket");
+ return;
+ }
+
+ // set socket options
+ socklen_t yes = 1;
+ if (::setsockopt(netserver_fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(socklen_t)) == -1) {
+ con_error << "Network can't set socket options!" << std::endl;
+ //perror("setsockopt");
+ return;
+ }
+
+ // Get the local adress to bind to
+ netserver_addr.sin_family = AF_INET;
+ netserver_addr.sin_port = htons(port);
+ if (host.size()) {
+ netserver_addr.sin_addr.s_addr = inet_addr(host.c_str());
+ if ( netserver_addr.sin_addr.s_addr == INADDR_NONE) {
+ con_error << "Network invalid address " << host << "!" << std::endl;
+ return;
+ }
+ } else {
+ netserver_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ memset(netserver_addr.sin_zero, '\0', sizeof(netserver_addr.sin_zero));
+
+ // bind the local address to the socket ( note the typecast)
+ if (::bind(netserver_fd, (struct sockaddr *) &netserver_addr, sizeof(struct sockaddr)) == -1) {
+ con_error << "Network can't bind to local address!" << std::endl;
+ //perror("bind");
+ return;
+ }
+
+ con_print << " Listening on " << inet_ntoa(netserver_addr.sin_addr) << ":" << ntohs(netserver_addr.sin_port) << std::endl;
+
// add the listening socket to the file descriptor set
- FD_SET(fd(), &serverset);
+ FD_ZERO(&serverset);
+ FD_SET(netserver_fd, &serverset);
- fdmax=fd();
+ netserver_error = false;
}
NetServer::~NetServer()
@@ -36,80 +89,49 @@ NetServer::~NetServer()
// delete all clients
std::list<NetClient *>:: iterator it;
for (it = clients.begin(); it != clients.end(); it++) {
+
// notify the game server
- server()->player_disconnect((*it)->player());
- con_print << (*it)->host() << ":" << (*it)->port() << " disconnected.\n";
+ if ((*it)->state() == NetClient::Connected)
+ server()->player_disconnect((*it)->player());
+
delete (*it);
}
clients.clear();
-}
-
-void NetServer::client_connect(int const clientfd, std::string const host, int const port)
-{
- NetClient *client = new NetClient(clientfd, host, port);
- if (client->error()) {
- con_warn << client->host() << ":" << client->port() << " connection failed!\n";
- delete(client);
- return;
- }
-
- clients.push_back(client);
- FD_SET(client->fd(), &serverset);
-
- con_print << client->host() << ":" << client->port() << " connected.\n";
-
- std::ostringstream netmsg;
-
- // 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()) {
- case Entity::Default:
- case Entity::Dynamic:
- case Entity::Controlable:
- netmsg << "ent ";
- (*it).second->serialize(netmsg);
- netmsg << "\n";
- client->send(netmsg.str());
- break;
- default:
- break;
- }
- }
-
- // mark player as dirty
- client->player()->player_dirty = true;
-
- // notify the game server
- server()->player_connect(client->player());
+ if (valid())
+ ::close(fd());
}
// remove disconnected clients
void NetServer::reap()
{
- std::list<NetClient *>:: iterator it;
- for (it = clients.begin(); it != clients.end(); it++) {
+ for (std::list<NetClient *>:: iterator it = clients.begin(); it != clients.end(); it++) {
NetClient *client = *it;
+
if (client->error()) {
- FD_CLR(client->fd(), &serverset);
// notify the game server
- server()->player_disconnect((*it)->player());
- con_print << client->host() << ":" << client->port() << " disconnected.\n";
+ if (client->state() == NetClient::Connected)
+ server()->player_disconnect((*it)->player());
// remove the client
clients.erase(it);
delete client;
- it=clients.begin();
-
+ it=clients.begin();
}
}
}
-void NetServer::frame(float seconds) {
+void NetServer::transmit()
+{
+ for (std::list<NetClient *>::iterator it = clients.begin(); it != clients.end(); it++) {
+ (*it)->transmit();
+ }
+}
+
+void NetServer::receive()
+{
if (error())
return;
@@ -118,52 +140,145 @@ void NetServer::frame(float seconds) {
timeout.tv_usec = 0;
fd_set readset = serverset;
- int nb = select(fdmax+1, &readset, NULL, NULL, &timeout);
- if (nb == 0)
- return;
-
+ int nb = select(fd()+1, &readset, NULL, NULL, &timeout);
if (nb == -1) {
con_error << "Network error on select()" << std::endl;
//perror("select");
abort();
+ return;
}
+
+ while (nb && FD_ISSET(fd(), &readset)) {
+ // receive incoming data
+ struct sockaddr_in client_addr;
+ socklen_t client_addr_len = sizeof(client_addr);
+ memset(recbuf, '\0', sizeof(recbuf));
+ ssize_t bytes_received = ::recvfrom(fd(), recbuf, FRAMESIZE-1, 0, (struct sockaddr *)&client_addr, &client_addr_len);
+ if (bytes_received == -1) {
+ con_error << "Network error on recvfrom()!" << std::endl;
+ abort();
+ return;
+ } else {
+ //con_debug << "Incoming data '" << recbuf << "'"<< bytes_received << " bytes" << std::endl;
+ }
- // accept incoming connections
- if(FD_ISSET(this->fd(), &readset)) {
- accept();
- }
+ // originator
+ std::string client_host (inet_ntoa(client_addr.sin_addr));
+ unsigned int client_port = ntohs(client_addr.sin_port);
+
+ // get messages from clients
+ bool msg_received = false;
- // get messages from clients
- for (std::list<NetClient *>::iterator it = clients.begin(); it != clients.end(); it++) {
- NetClient *client = *it;
- if (client->fd() > fdmax)
- fdmax = client->fd();
- if (FD_ISSET(client->fd(), &readset) && !client->error()) {
- client->receive();
- while (client->has_messages()) {
- std::string message;
- client->retreive(message);
- parse_incoming_message(client, message);
+ for (std::list<NetClient *>::iterator it = clients.begin(); it != clients.end() && !msg_received; it++) {
+ NetClient *client = *it;
+
+ if ((client->host() == client_host) && (client->port() == (int) client_port)) {
+ // receive data
+ client->receive(recbuf);
+
+ // process parsed messages
+ while (client->has_messages()) {
+ std::string message;
+ client->retreive(message);
+ parse_incoming_message(client, message);
+ }
+
+ msg_received = true;
+ }
+ }
+
+ if (!msg_received) {
+ // new connection
+ // FIXME maxclients
+ NetClient *client = client_connect(client_host , client_port);
+
+ if (client) {
+ // receive data
+ client->receive(recbuf);
+
+ // process parsed messages
+ while (client->has_messages()) {
+ std::string message;
+ client->retreive(message);
+ parse_incoming_message(client, message);
+ }
}
}
+
+ readset = serverset;
+ nb = select(fd(), &readset, NULL, NULL, &timeout);
+ if (nb == -1) {
+ con_error << "Network error on select()" << std::endl;
+ //perror("select");
+ abort();
+ return;
+ }
}
// remove dead connections
+ // FIXME timeout
reap();
}
+
+NetClient * NetServer::client_connect(std::string const host, int const port)
+{
+ con_debug << "client_connect " << host << ":" << port << "\n";
+
+ NetClient *client = new NetClient(host, port);
+ if (client->error()) {
+ con_warn << client->host() << ":" << client->port() << " connection failed!\n";
+ delete(client);
+ return 0;
+ }
+
+ clients.push_back(client);
+
+ std::ostringstream netmsg;
+ netmsg.str("");
+ netmsg << "msg info Receiving data from remote server...\n";
+ client->send(netmsg.str());
+
+ // 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()) {
+ case Entity::Default:
+ case Entity::Dynamic:
+ case Entity::Controlable:
+ netmsg << "ent ";
+ (*it).second->serialize(netmsg);
+ netmsg << "\n";
+
+ client->send(netmsg.str());
+
+ break;
+ default:
+ break;
+ }
+ }
+
+ transmit();
+
+ client->player()->player_dirty = false;
+
+ return client;
+}
+
void NetServer::send(NetClient * client, std::string const & message)
{
client->send(message);
}
// send a message to all clients
-void NetServer::broadcast(std::string const & message, int ignorefd)
+void NetServer::broadcast(std::string const & message, Player *ignore_player)
{
//std::cout << "NetServer: " << osstream.str();
for (std::list<NetClient *>::iterator it = clients.begin(); it != clients.end(); it++) {
NetClient *client = *it;
- if (!client->error() && client->fd() != ignorefd)
+ if (!client->error() && (client->state() == NetClient::Connected) && client->player() != ignore_player)
client->send(message);
}
}
@@ -172,14 +287,14 @@ void NetServer::broadcast(std::string const & message, int ignorefd)
NetClient *NetServer::find_client(Player const *player)
{
for (std::list<NetClient *>::iterator it = clients.begin(); it != clients.end(); it++) {
- if ((*it)->fd() == (int) player->id()) {
+ if ((*it)->player() == player) {
return (*it);
}
}
return 0;
}
-// parse server messages
+// parse incoming client messages
/**
* The following incoming protocol messages are parsed;
*
@@ -206,6 +321,20 @@ void NetServer::parse_incoming_message(NetClient *client, const std::string & me
return;
}
+ // pif - update player information
+ // pif is the first command expected from the client
+ if (command == "pif") {
+ client->player()->recieve_client_update(msgstream);
+
+ if (client->state() == NetClient::Connecting) {
+ client->client_state = NetClient::Connected;
+ server()->player_connect(client->player());
+ }
+ }
+
+ if (client->state() != NetClient::Connected)
+ return;
+
// cmd
if (command == "cmd") {
if (message.size() > command.size()+1) {
@@ -233,11 +362,6 @@ void NetServer::parse_incoming_message(NetClient *client, const std::string & me
return;
}
- // pif - update player information
- if (command == "pif") {
- client->player()->recieve_client_update(msgstream);
- }
-
// say
if (command == "say") {
if (message.size() > command.size()+1) {
@@ -249,43 +373,6 @@ void NetServer::parse_incoming_message(NetClient *client, const std::string & me
return;
}
- /*
- // name
- if (command == "name") {
- std::string name;
- if (msgstream >> name) {
- if (name.size() > 16)
- name = name.substr(0,16);
- if (name != client->player()->name()) {
- std::ostringstream osstream;
- osstream << "msg info " << client->player()->name() << " renamed to " << name << "\n";
- broadcast(osstream.str());
- con_print << client->player()->name() << " renamed to " << name << std::endl;
- client->player()->player_name = name;
- }
- }
- return;
- }
-
- if (command == "list_players") {
- std::ostringstream osstream;
- for (std::list<NetClient *>::iterator it = clients.begin(); it != clients.end(); it++) {
- osstream << "msg info " << (*it)->player()->name() << " " << (*it)->host() << ":" << (*it)->port() << "\n";
- }
- osstream << "msg info " << clients.size() << " connected players\n" << std::endl;
- send(client, osstream.str());
- }
-
- if (command == "help") {
- send(client, "msg info Available protocol messages:\n");
- send(client, "msg info help - shows this help message\n");
- send(client, "msg info name [nickname] - changes your nickname\n");
- send(client, "msg info say [text] - say something on the public channel\n");
- send(client, "msg info cmd [text] - execute a game command\n");
- send(client, "msg info list_players - shows a list of connected players\n");
- send(client, "msg info disconnect - disconnect\n");
- }
- */
}
}
diff --git a/src/core/netserver.h b/src/core/netserver.h
index 4de87be..df098df 100644
--- a/src/core/netserver.h
+++ b/src/core/netserver.h
@@ -12,35 +12,56 @@
#include <list>
#include <string>
-#include "net/tcpserver.h"
+#include "core/net.h"
#include "core/netclient.h"
+#include "core/player.h"
namespace core
{
/// Network server
-class NetServer : public net::TCPServer
+class NetServer
{
public:
NetServer(std::string const host, unsigned int const port);
- virtual ~NetServer();
+ ~NetServer();
- /// run one server frame
- void frame(float seconds);
+/*----- inspectors ------------------------------------------------ */
- /// broadcast a message to all clients
- void broadcast(std::string const & message, int ignorefd=-1);
+ /// Returns true if the TCP server has a valid file descriptor
+ inline bool valid() const { return netserver_fd != -1; }
+
+ /// Returns true if the TCP server has an invalid file descriptor
+ inline bool invalid() const { return netserver_fd == -1; }
+
+ /// Returns the error state of the TCP server
+ inline bool error() const { return netserver_error; }
+
+ /// Return the socket file descriptor
+ inline int fd() const { return netserver_fd; }
+
+/*----- mutators -------------------------------------------------- */
+
+ /// receive data from clients
+ void receive();
- /// send a message to a client
+ /// transmit data to clients
+ void transmit();
+
+ /// broadcast network data to all clients
+ void broadcast(std::string const & message, Player *ignore_player=0);
+
+ /// send network data to one client
void send(NetClient * client, std::string const & message);
/// find the client corresponding to a player
NetClient *find_client(Player const *player);
std::list<NetClient *> clients;
+
protected:
- /// called by accept() when a new client connects
- virtual void client_connect(int const clientfd, std::string const host, int const port);
+ /// called when a new client connects
+ NetClient *client_connect(std::string const host, int const port);
/// remove terminated clients
void reap();
@@ -48,8 +69,15 @@ protected:
/// parse incoming client messages
void parse_incoming_message(NetClient *client, const std::string & message);
+private:
+ bool netserver_error;
+ int netserver_fd;
+ struct sockaddr_in netserver_addr;
+
fd_set serverset;
int fdmax;
+
+ char recbuf[FRAMESIZE];
};
}
diff --git a/src/core/player.cc b/src/core/player.cc
index 4c4616a..b89da99 100644
--- a/src/core/player.cc
+++ b/src/core/player.cc
@@ -73,8 +73,7 @@ void Player::recieve_client_update(std::istream &is)
n += c;
if (n.size())
- player_name = n;
-
+ player_name = n;
}
void Player::serialize_server_update(std::ostream & os) const