From 715d0c3952a3a1d59b64074e472d0a9a3b414351 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Thu, 14 Feb 2008 18:04:25 +0000 Subject: dedicated server accepts incoming connections --- src/core/netserver.cc | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 src/core/netserver.cc (limited to 'src/core/netserver.cc') 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 +#include + +#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:: 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:: 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::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::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::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; + } +} + +} -- cgit v1.2.3