Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/Masterserver_FS18/src/libraries/network/Server.cc @ 11983

Last change on this file since 11983 was 11829, checked in by mdedial, 7 years ago

WIP 22.03.18: Begin documenting server-side code

  • Property svn:eol-style set to native
File size: 11.1 KB
RevLine 
[1502]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
[3084]23 *      Oliver Scheuss
[1502]24 *   Co-authors:
25 *      ...
26 *
27 */
28
29//
30// C++ Implementation: Server
31//
32// Description:
33//
34//
35// Author:  Oliver Scheuss, (C) 2007
36//
37// Copyright: See COPYING file that comes with this distribution
38//
39//
40
41#include "Server.h"
42
[5749]43#define WIN32_LEAN_AND_MEAN
[2773]44#include <enet/enet.h>
[1755]45#include <cassert>
[3214]46#include <string>
[1502]47
[5929]48#include "util/Clock.h"
[8858]49#include "util/Output.h"
[7284]50#include "core/command/Executor.h"
[1735]51#include "packet/Chat.h"
[3214]52#include "packet/ClassID.h"
53#include "packet/DeleteObjects.h"
54#include "packet/FunctionIDs.h"
55#include "packet/Gamestate.h"
[1735]56#include "packet/Welcome.h"
[3084]57#include "FunctionCallManager.h"
[3214]58#include "GamestateManager.h"
[1502]59
[2171]60namespace orxonox
[1502]61{
[2087]62  const unsigned int MAX_FAILURES = 20;
[1747]63
[1502]64  /**
65  * Constructor for default values (bindaddress is set to ENET_HOST_ANY
66  *
67  */
[7163]68  Server::Server()
69  {
[11829]70    this->timeSinceLastUpdate_ = 0;
[1502]71  }
[1747]72
[11829]73  /**
74  * Constructor
75  * @param port Port to listen on
76  */
[7163]77  Server::Server(int port)
78  {
[11829]79    this->setPort(port);
80    this->timeSinceLastUpdate_ = 0;
[1502]81  }
[11829]82
[1502]83  /**
84  * Constructor
85  * @param port Port to listen on
86  * @param bindAddress Address to listen on
87  */
[7163]88  Server::Server(int port, const std::string& bindAddress)
89  {
[11829]90    this->setPort(port);
91    this->setBindAddress(bindAddress);
92    this->timeSinceLastUpdate_ = 0;
[1502]93  }
94
95  /**
[1907]96  * @brief Destructor
97  */
[7163]98  Server::~Server()
99  {
[1907]100  }
[1502]101
102  /**
103  * This function opens the server by creating the listener thread
104  */
[7163]105  void Server::open()
106  {
107    Host::setActive(true);
[8858]108    orxout(verbose, context::network) << "opening server" << endl;
[3214]109    this->openListener();
[8858]110
[7801]111    /* make discoverable on LAN */
[7163]112    LANDiscoverable::setActivity(true);
[10622]113    LANDiscoverable::updateClientNumber(0);
[7801]114
115    /* make discoverable on WAN */
116    WANDiscoverable::setActivity(true);
[10622]117    WANDiscoverable::updateClientNumber(0);
[7801]118
119    /* done */
[1502]120    return;
121  }
122
123  /**
124  * This function closes the server
125  */
[7163]126  void Server::close()
127  {
128    Host::setActive(false);
[8858]129    orxout(verbose, context::network) << "closing server" << endl;
[3214]130    this->disconnectClients();
131    this->closeListener();
[7801]132
133    /* tell master server we're closing */
[8858]134    orxout(internal_info, context::network) << "disconnecting." << endl;
135    WANDiscoverable::setActivity(false);
136    orxout(internal_info, context::network) << "disconnecting done" << endl;
[7801]137
[7163]138    LANDiscoverable::setActivity(false);
[1502]139    return;
140  }
141
142  /**
143  * Run this function once every tick
144  * calls processQueue and updateGamestate
145  * @param time time since last tick
146  */
[7163]147  void Server::update(const Clock& time)
148  {
[3304]149    // receive incoming packets
[3214]150    Connection::processQueue();
[7801]151
[7163]152    // receive and process incoming discovery packets
153    LANDiscoverable::update();
[6417]154
[11829]155    if (GamestateManager::hasPeers())
[3214]156    {
[3304]157      // process incoming gamestates
158      GamestateManager::processGamestates();
[7801]159      FunctionCallManager::processBufferedFunctionCalls();
[6417]160
[3304]161      // send function calls to clients
[11829]162      FunctionCallManager::sendCalls(static_cast<Host*>(this));
[6417]163
[11829]164      // this steers our network frequency
165      timeSinceLastUpdate_ += time.getDeltaTime();
166      if(timeSinceLastUpdate_ >= NETWORK_PERIOD)
[3304]167      {
[11829]168        timeSinceLastUpdate_ -= static_cast<unsigned int>(timeSinceLastUpdate_ / NETWORK_PERIOD) * NETWORK_PERIOD;
[3304]169        updateGamestate();
170      }
[1502]171    }
172  }
[1747]173
[7801]174  void Server::queuePacket(ENetPacket *packet, int clientID, uint8_t channelID)
[7163]175  {
[7801]176    ServerConnection::addPacket(packet, clientID, channelID);
[1735]177  }
[6417]178
[2087]179  /**
[11829]180   * Return ping time to client in milliseconds.
[2087]181   */
[7163]182  unsigned int Server::getRTT(unsigned int clientID)
183  {
[11829]184    // TODO: Implement
[8327]185    return 0;
[2087]186  }
[6417]187
[11829]188  /**
189   * Print ping time to client in milliseconds.
190   */
[5961]191  void Server::printRTT()
192  {
[11829]193    // TODO: Implement
[5961]194  }
[1502]195
196  /**
[11829]197   * Return packet loss ratio to client (scales from 0 to 1).
[2087]198   */
[8351]199  float Server::getPacketLoss(unsigned int clientID)
[7163]200  {
[11829]201    // TODO: Implement
[8327]202    return 0.;
[2087]203  }
[1502]204
205  /**
[11829]206   * Take a new snapshot of the gamestate and send it to the clients.
207   */
[7163]208  void Server::updateGamestate()
209  {
[11829]210    if(this->clientIDs_.size() == 0)
211    {
212      // no client connected
[3304]213      return;
[11829]214    }
[3304]215    GamestateManager::update();
[7801]216    sendGameStates();
[1907]217    sendObjectDeletes();
[1502]218  }
219
220  /**
[11829]221   * Send the current gamestate to all peers.
222   */
[7801]223  bool Server::sendGameStates()
[7163]224  {
[7801]225    std::vector<packet::Gamestate*> gamestates = GamestateManager::getGamestates();
[11829]226    for(packet::Gamestate* gamestate : gamestates)
[7801]227    {
[11071]228      gamestate->send(static_cast<Host*>(this));
[7801]229    }
[1502]230    return true;
231  }
[1747]232
[7801]233
[11829]234  /**
235   * Send 'DeleteObjects' packet
236   */
[7163]237  bool Server::sendObjectDeletes()
238  {
[11829]239    // no client connected
240    if(this->clientIDs_.size() == 0)
241    {
[2662]242      return true;
[11829]243    }
244
[1907]245    packet::DeleteObjects *del = new packet::DeleteObjects();
246    if(!del->fetchIDs())
[5929]247    {
248      delete del;
[1907]249      return true;  //everything ok (no deletes this tick)
[5929]250    }
[11829]251
[8327]252    del->setPeerID(NETWORK_PEER_ID_BROADCAST);
[11829]253    if (!del->send( static_cast<Host*>(this)))
254    {
[8858]255      orxout(internal_warning, context::network) << "Server: could not broadcast deleteObjects packet" << endl;
[11829]256    }
257
258    // TODO: Possible memory leak?
259    // del is allocated but only deleted if fetchIDs() returns false
260
[1907]261    return true;
262  }
[1747]263
[11829]264  /**
265   * Add a new peer to the server.
266   */
[8327]267  void Server::addPeer(uint32_t peerID)
[7163]268  {
[2087]269    // inform all the listeners
[8327]270    this->clientIDs_.push_back(peerID);
[10622]271    WANDiscoverable::updateClientNumber(this->clientIDs_.size());
272    LANDiscoverable::updateClientNumber(this->clientIDs_.size());
273
[8327]274    ClientConnectionListener::broadcastClientConnected(peerID);
275    GamestateManager::addPeer(peerID);
[2087]276
[8858]277    orxout(internal_info, context::network) << "Server: added client id: " << peerID << endl;
[10622]278
[8327]279    createClient(peerID);
[11829]280  }
[1747]281
[11829]282  /**
283   * Remove a peer from the server.
284   */
[8327]285  void Server::removePeer(uint32_t peerID)
[5929]286  {
[8858]287    orxout(verbose, context::network) << "removing client from list" << endl;
[11829]288
289    // erase the peer from the list
290    std::vector<uint32_t>::iterator it;
291    for(it=this->clientIDs_.begin(); it!=this->clientIDs_.end(); ++it)
[5929]292    {
[11829]293      if(*it == peerID)
294      {
295        this->clientIDs_.erase(it);
296        break;
297      }
[8327]298    }
[10622]299
[11829]300    // TODO: What happens if no peer with this ID is found?
301    // Should probably at least log
302
303    WANDiscoverable::updateClientNumber(this->clientIDs_.size());
304    LANDiscoverable::updateClientNumber(this->clientIDs_.size());
305
306    // Send 'clientDisconnected' message
307    ClientConnectionListener::broadcastClientDisconnected(peerID);
308
309    GamestateManager::removePeer(peerID);
[5929]310  }
[8858]311
[11829]312  /**
313   * Process an incoming packet.
314   */
[7801]315  void Server::processPacket(packet::Packet* packet)
316  {
[11829]317    if(packet->isReliable())
[7801]318    {
[11829]319      if(this->getLastReceivedGamestateID(packet->getPeerID()) >= packet->getRequiredGamestateID())
320      {
[7801]321        packet->process(static_cast<Host*>(this));
[11829]322      }
[7801]323      else
[11829]324      {
[7801]325        this->packetQueue_.push_back(packet);
[11829]326      }
[7801]327    }
328    else
[11829]329    {
[7801]330      packet->process(static_cast<Host*>(this));
[11829]331    }
[7801]332  }
[5929]333
[11829]334  /**
335   * Create a client.
336   */
[7163]337  bool Server::createClient(int clientID)
338  {
[6417]339
[3084]340    // synchronise class ids
[8327]341    syncClassid(clientID);
[6417]342
[3084]343    // now synchronise functionIDs
344    packet::FunctionIDs *fIDs = new packet::FunctionIDs();
[7801]345    fIDs->setPeerID(clientID);
[11829]346    bool b = fIDs->send(static_cast<Host*>(this));
[3084]347    assert(b);
[11829]348    // TODO: assert probably isn't the way to go here, as a packet which fails to send will crash the game...
[6417]349
[7801]350    GamestateManager::setSynched(clientID);
[8858]351
[11829]352    // Send 'Welcome' packet to client
[8858]353    orxout(verbose, context::network) << "sending welcome" << endl;
[8706]354    packet::Welcome *w = new packet::Welcome(clientID);
[8327]355    w->setPeerID(clientID);
[11829]356    b = w->send(static_cast<Host*>(this));
[1907]357    assert(b);
[11829]358    // TODO: assert probably isn't the way to go here, as a packet which fails to send will crash the game...
359
[11103]360    (void)b; // avoid compiler warning
[1502]361    return true;
362  }
[6417]363
[11829]364  /**
365   * Disconnect a client.
366   */
367  void Server::disconnectClient(uint32_t clientID)
[7163]368  {
[11829]369    ServerConnection::disconnectClient(clientID);
370    GamestateManager::removePeer(clientID);
[1502]371  }
[2087]372
[8858]373  /**
374   * @brief Sends a chat message to the given target ID.
375   * @param message message to be sent
376   * @param sourceID the ID of the sender
377   * @param targetID the ID of the receiver
378   */
379  void Server::doSendChat(const std::string& message, unsigned int sourceID, unsigned int targetID)
[7163]380  {
[8858]381    // check if the target exists. just ignore the message otherwise
382    if (!this->isValidTarget(targetID)) // TODO: remove this if an invalid clientIDs don't trigger assertions anymore
[11829]383    {
[8858]384      return;
[11829]385    }
[8858]386
387    // send the message to the target
388    packet::Chat* packet = new packet::Chat(message, sourceID, targetID);
389    packet->setPeerID(targetID);
[11829]390    packet->send(static_cast<Host*>(this));
[8858]391
392    // if the target is (or includes) this host as well, call the parent function which passes the message to the listeners
393    if (targetID == NETWORK_PEER_ID_BROADCAST || targetID == Host::getPlayerID())
[11829]394    {
[8858]395      Host::doReceiveChat(message, sourceID, targetID);
[11829]396    }
[2087]397  }
398
[8858]399  /**
400   * @brief Gets called if a packet::Chat packet is received. Forwards the packet to the target
401   * and calls the parent function if necessary.
402   */
403  void Server::doReceiveChat(const std::string& message, unsigned int sourceID, unsigned int targetID)
[7163]404  {
[8858]405      this->doSendChat(message, sourceID, targetID);
[2087]406  }
407
[8858]408  /**
409   * @brief Returns true if the target ID is in the list of clients (or if it
410   * corresponds to the broadcast or the server ID).
411   */
412  bool Server::isValidTarget(unsigned int targetID)
[7163]413  {
[11829]414    // Broadcast or server ID are okay
[8858]415    if (targetID == NETWORK_PEER_ID_BROADCAST || targetID == NETWORK_PEER_ID_SERVER)
[11829]416    {
[8858]417      return true;
[11829]418    }
[2087]419
[11829]420    // IDs in the client list are okay also
421    for(uint32_t id : this->clientIDs_)
422    {
423      if(id == targetID)
424      {
[8858]425        return true;
[11829]426      }
427    }
[8858]428
429    return false;
[1907]430  }
[1747]431
[7163]432  void Server::syncClassid(unsigned int clientID)
433  {
[3214]434    packet::ClassID *classid = new packet::ClassID();
[7801]435    classid->setPeerID(clientID);
[11829]436    // TODO: Better to do this with a for loop
437    int failures = 0;
438    while(!classid->send(static_cast<Host*>(this)) && failures < 10)\
439    {
[3214]440      failures++;
441    }
442    assert(failures<10);
[11829]443    // TODO: assert probably isn't the way to go here, as 10 failed packets will crash the game...
[8858]444    orxout(verbose, context::network) << "syncClassid:\tall synchClassID packets have been sent" << endl;
[3214]445  }
446
[1502]447}
Note: See TracBrowser for help on using the repository browser.