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-02-14 18:04:25 +0000
committerStijn Buys <ingar@osirion.org>2008-02-14 18:04:25 +0000
commit715d0c3952a3a1d59b64074e472d0a9a3b414351 (patch)
treea5d0ddd0613caaf4f9fe01f9a3bd34e823651ad5 /src/core/netserver.cc
parent83e8023c5e46635753a609329cf9805a3520001e (diff)
dedicated server accepts incoming connections
Diffstat (limited to 'src/core/netserver.cc')
-rw-r--r--src/core/netserver.cc268
1 files changed, 268 insertions, 0 deletions
diff --git a/src/core/netserver.cc b/src/core/netserver.cc
new file mode 100644
index 0000000..c37b71d
--- /dev/null
+++ b/src/core/netserver.cc
@@ -0,0 +1,268 @@
+/*
+ net/netserver.h
+ This file is part of the Osirion project and is distributed under
+ the terms of the GNU General Public License version 2
+*/
+
+#include <iostream>
+#include <sstream>
+
+#include "sys/sys.h"
+#include "core/netclient.h"
+#include "core/netserver.h"
+#include "core/cvar.h"
+#include "core/func.h"
+#include "core/core.h"
+
+namespace core
+{
+
+NetServer::NetServer(std::string const host, unsigned int const port) :
+ net::TCPServer(host, port)
+{
+ FD_ZERO(&serverset);
+ // add the listening socket to the file descriptor set
+ FD_SET(fd(), &serverset);
+
+ fdmax=fd();
+}
+
+NetServer::~NetServer()
+{
+ con_print << "Shutting down network..." << std::endl;
+
+ // delete all clients
+ std::list<NetClient *>:: iterator it;
+ for (it = clients.begin(); it != clients.end(); it++) {
+ // notify the game
+ if (core::connected()) {
+ core::game()->player_disconnect((*it)->player());
+ con_print << (*it)->player().name << " disconnected."<< std::endl;
+ }
+ 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 " << client->fd() << " " <<
+ client->host() << ":" << client->port() << " connection failed!" << std::endl;
+ delete(client);
+ return;
+ }
+
+ clients.push_back(client);
+ FD_SET(client->fd(), &serverset);
+
+ // TODO send infos
+
+ con_print << client->player().name << " connected."<< std::endl;
+
+ // notify the game
+ if (core::game())
+ core::game()->player_connect(client->player());
+
+ // BROADCAST connect message
+ std::ostringstream osstream;
+ osstream << "msg info " << client->player().name << " connected."<< std::endl;
+ broadcast(osstream);
+}
+
+// remove disconnected clients
+void NetServer::reap()
+{
+ std::list<NetClient *>:: iterator it;
+ for (it = clients.begin(); it != clients.end(); it++) {
+ NetClient *client = *it;
+ if (client->error()) {
+ FD_CLR(client->fd(), &serverset);
+
+ // BROADCAST disconnect message
+ std::ostringstream osstream;
+ osstream << "msg info " << client->player().name << " disconnected."<< std::endl;
+ broadcast(osstream);
+
+ // notify the game
+ if (core::game())
+ core::game()->player_disconnect(client->player());
+
+ con_print << client->player().name << " disconnected."<< std::endl;
+
+ // remove the client
+ clients.erase(it);
+ delete client;
+ it=clients.begin();
+
+ }
+ }
+}
+
+
+void NetServer::frame(float seconds) {
+ if (error())
+ return;
+
+ timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ fd_set readset = serverset;
+
+ int nb = select(fdmax+1, &readset, NULL, NULL, &timeout);
+ if (nb == 0)
+ return;
+
+ if (nb == -1) {
+ con_error << "Network error on select()" << std::endl;
+ perror("select");
+ abort();
+ }
+
+ // accept incoming connections
+ if(FD_ISSET(this->fd(), &readset)) {
+ accept();
+ }
+
+ // 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);
+ }
+ }
+ }
+
+ // remove dead connections
+ reap();
+}
+
+// send a message to one client
+void NetServer::send(NetClient * client, std::ostringstream &osstream) {
+ // FIXME large messages
+ //std::cout << "NetServer: " << osstream.str();
+ client->send(osstream.str());
+ osstream.str("");
+}
+
+void NetServer::send(NetClient * client, std::string message) {
+ //std::cout << "NetServer: " << message;
+ client->send(message);
+}
+
+// send a message to all clients
+void NetServer::broadcast(std::ostringstream &osstream, int ignorefd)
+{
+ //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)
+ client->send(osstream.str());
+ }
+ osstream.str("");
+}
+
+void NetServer::parse_incoming_message(NetClient *client, const std::string & message)
+{
+ std::stringstream msgstream(message);
+
+ std::string command;
+ msgstream >> command;
+
+ // disconnect
+ if (command == "disconnect") {
+ client->abort();
+ return;
+ }
+
+ // say
+ if (command == "say") {
+ if (message.size() > command.size()+1) {
+ std::ostringstream osstream;
+ osstream << "msg public " << client->player().name << " " << message.substr(command.size()+1) << std::endl;
+ broadcast(osstream);
+ con_print << client->player().name << " " << message.substr(command.size()+1) << std::endl;
+ }
+ return;
+ }
+
+ // name is an alias for set 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 << std::endl;
+ broadcast(osstream);
+ client->player().name = name;
+ con_print << client->player().name << " renamed to " << name << std::endl;
+ }
+ }
+ return;
+ }
+
+ if (command == "list_players") {
+ std::ostringstream osstream;
+ for (std::list<NetClient *>::iterator it = clients.begin(); it != clients.end(); it++) {
+ osstream << "msg info client " << (*it)->player().name << " " << (*it)->host() << ":" << (*it)->port() << std::endl;
+ }
+ osstream << "msg info client " << clients.size() << " players" << std::endl;
+ send(client, osstream);
+ }
+
+ if (command == "help") {
+ send(client, "msg info Available commands:\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 list_players - shows a list of connected players\n");
+ send(client, "msg info disconnect - disconnect\n");
+ }
+
+ // execute game functions
+ if (game() && game()->connected) {
+ Func f = func::find(command);
+ if (f) {
+ if (f->flags && func::Game) {
+ GameFuncPtr function = (GameFuncPtr) f->ptr;
+ function(client->player(), msgstream);
+ } else {
+ // FIXME rcon
+ // FuncPtr function = (FuncPtr) f->ptr;
+ // function(msgstream);
+ }
+ return;
+ }
+ }
+
+ // TODO rcon
+}
+
+void NetServer::parse_client_variable(NetClient * client, const std::string varname, std::istringstream &istringstream)
+{
+ if (varname=="name") {
+ std::string name;
+ if (istringstream >> name) {
+ std::ostringstream osstream;
+ if (name.size() > 16)
+ name = name.substr(0,16);
+ if (name != client->player().name) {
+ osstream << "msg info " << client->player().name << " renamed to " << name << std::endl;
+ broadcast(osstream);
+ client->player().name = name;
+ }
+ }
+ return;
+ }
+}
+
+}