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-21 19:25:11 +0000
committerStijn Buys <ingar@osirion.org>2008-03-21 19:25:11 +0000
commit2314c27dd650dc02c0b5bdd3bef75818393a9ab5 (patch)
tree231815c866a1330338d976480284250e99207554 /src/core/netserver.cc
parent7e99fac4552b402034e5fc3e833cbe8c274f95ce (diff)
switched to UDP networking
Diffstat (limited to 'src/core/netserver.cc')
-rw-r--r--src/core/netserver.cc331
1 files changed, 209 insertions, 122 deletions
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");
- }
- */
}
}