Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/Masterserver_FS18/src/libraries/network/Connection.cc @ 11842

Last change on this file since 11842 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.9 KB
RevLine 
[3214]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:
23 *      Oliver Scheuss
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "Connection.h"
30
31#include <cassert>
[7801]32#include <deque>
[5929]33#define WIN32_LEAN_AND_MEAN
[3214]34#include <enet/enet.h>
[7801]35#include <boost/thread.hpp>
36#include <boost/thread/mutex.hpp>
37#include <boost/date_time.hpp>
38
[3214]39#include "packet/Packet.h"
[8327]40#include <util/Sleep.h>
[3214]41
42namespace orxonox
43{
[8327]44  const boost::posix_time::millisec NETWORK_COMMUNICATION_THREAD_WAIT_TIME(200);
45  const unsigned int                NETWORK_DISCONNECT_TIMEOUT = 500;
[3214]46
[11829]47  /**
48   * Constructor
49   * @param firstPeerId The initial value of nextPeerID_
50   */
[8327]51  Connection::Connection(uint32_t firstPeerID):
[11071]52    host_(nullptr), bCommunicationThreadRunning_(false), nextPeerID_(firstPeerID)
[3214]53  {
[11829]54    // Global initialization of ENet
[3214]55    enet_initialize();
[11829]56
57    // Register enet_deinitialize to be executed when the program exits normally
[3214]58    atexit(enet_deinitialize);
[11829]59
60    // Create mutexes for incoming and outgoing events
[7801]61    this->incomingEventsMutex_ = new boost::mutex;
62    this->outgoingEventsMutex_ = new boost::mutex;
[3214]63  }
64
[11829]65  /**
66   * Destructor
67   */
[7801]68  Connection::~Connection()
69  {
[11829]70    // Delete the mutexes
[7801]71    delete this->incomingEventsMutex_;
72    delete this->outgoingEventsMutex_;
[11829]73
74    // TODO: Why is enet_deinitialize() not called here?
75    // Would make sense, since its counterpart, enet_initialize(), is called in the constructor.
[3214]76  }
77
[11829]78  /**
79   * Start the main communication thread.
80   */
[7801]81  void Connection::startCommunicationThread()
82  {
83    this->bCommunicationThreadRunning_ = true;
84    this->communicationThread_ = new boost::thread(&Connection::communicationThread, this);
[3214]85  }
[7801]86 
[11829]87  /**
88   * Stop the main communication thread.
89   */
[7801]90  void Connection::stopCommunicationThread()
91  {
92    this->bCommunicationThreadRunning_ = false;
[11829]93    // Wait for peaceful termination
94    if(!this->communicationThread_->timed_join(NETWORK_COMMUNICATION_THREAD_WAIT_TIME))
[7801]95    {
[11829]96      // Force thread to stop if the waiting time runs out.
[7801]97      this->communicationThread_->interrupt();
98    }
99    delete this->communicationThread_;
100  }
[3214]101
[11829]102  /**
103   * Send an outgoing event of type 'disconnectPeer'.
104   * @param peerID The peer to which the event is sent
105   */
[8327]106  void Connection::disconnectPeer(uint32_t peerID)
[7801]107  {
[11071]108    outgoingEvent outEvent = { peerID, OutgoingEventType::disconnectPeer, nullptr, 0 };
[7801]109   
110    this->outgoingEventsMutex_->lock();
111    this->outgoingEvents_.push_back(outEvent);
112    this->outgoingEventsMutex_->unlock();
[3214]113  }
[11829]114
115  /**
116   * Send an outgoing event of type 'disconnectPeers'.
117   */
[8327]118  void Connection::disconnectPeers()
119  {
[11071]120    outgoingEvent outEvent = { 0, OutgoingEventType::disconnectPeers, nullptr, 0 };
[8327]121   
122    this->outgoingEventsMutex_->lock();
123    this->outgoingEvents_.push_back(outEvent);
124    this->outgoingEventsMutex_->unlock();
125  }
[3214]126
[11829]127  /**
128   * Send a packet.
129   * @param packet Pointer to the packet to send
130   * @param peerID The peer to which the event is sent
131   * @param channelId The channel ID
132   */
[8327]133  void Connection::addPacket(ENetPacket* packet, uint32_t peerID, uint8_t channelID)
[7801]134  {
[11071]135    outgoingEvent outEvent = { peerID, OutgoingEventType::sendPacket, packet, channelID };
[7801]136   
137    this->outgoingEventsMutex_->lock();
138    this->outgoingEvents_.push_back(outEvent);
139    this->outgoingEventsMutex_->unlock();
[3214]140  }
[7801]141 
[11829]142  /**
143   * Send a broadcast packet.
144   * @param packet Pointer to the packet to send
145   * @param channelId The channel ID
146   */
[7801]147  void Connection::broadcastPacket(ENetPacket* packet, uint8_t channelID)
148  {
[11071]149    outgoingEvent outEvent = { 0, OutgoingEventType::broadcastPacket, packet, channelID };
[7801]150   
151    this->outgoingEventsMutex_->lock();
152    this->outgoingEvents_.push_back(outEvent);
153    this->outgoingEventsMutex_->unlock();
154  }
[3214]155
[7801]156 
[11829]157  /**
158   * Main communication thread
159   */
[7801]160  void Connection::communicationThread()
161  {
162    ENetEvent event;
163   
[11829]164    while(this->bCommunicationThreadRunning_)
[7801]165    {
166      // Receive all pending incoming Events (such as packets, connects and disconnects)
[11829]167      while(enet_host_check_events(this->host_, &event ) > 0)
[7801]168      {
[11829]169        this->processIncomingEvent(event);
[7801]170      }
171     
[11829]172      // Sleep for 1ms
173      // TODO: Why?
[8327]174      msleep(1);
175     
[7801]176      // Send all waiting outgoing packets
[11829]177      // TODO: Why do we need a mutex to read a single variable?
[7801]178      this->outgoingEventsMutex_->lock();
179      uint32_t outgoingEventsCount = this->outgoingEvents_.size();
180      this->outgoingEventsMutex_->unlock();
[11829]181
182      // TODO: Not convinced about how mutexes are used here, seems kinda pointless
183      while(outgoingEventsCount > 0)
[7801]184      {
185        this->outgoingEventsMutex_->lock();
186        outgoingEvent outEvent = this->outgoingEvents_.front();
187        this->outgoingEvents_.pop_front();
188        this->outgoingEventsMutex_->unlock();
189       
[11829]190        this->processOutgoingEvent(outEvent);
[8327]191       
[7801]192        this->outgoingEventsMutex_->lock();
193        outgoingEventsCount = this->outgoingEvents_.size();
194        this->outgoingEventsMutex_->unlock();
195      }
196     
197      // Wait for incoming events (at most NETWORK_WAIT_TIMEOUT ms)
[11829]198      if(enet_host_service(this->host_, &event, NETWORK_WAIT_TIMEOUT) > 0)
[7801]199      {
[11829]200        this->processIncomingEvent(event);
[7801]201      }
202    }
[3214]203  }
[8327]204 
[11829]205  /**
206   * Handle an incoming event.
207   * @param event The incoming event
208   */
[8327]209  void Connection::processIncomingEvent(ENetEvent& event)
210  {
211    incomingEvent inEvent;
212    // preprocess event
[11829]213    switch(event.type)
[8327]214    {
215      case ENET_EVENT_TYPE_CONNECT:
216        inEvent = preprocessConnectEvent(event);
217        break;
218      case ENET_EVENT_TYPE_RECEIVE:
219        inEvent = preprocessReceiveEvent(event);
220        break;
221      case ENET_EVENT_TYPE_DISCONNECT:
222        inEvent = preprocessDisconnectEvent(event);
223        break;
224      case ENET_EVENT_TYPE_NONE:
225      default:
226        return;
227    }
228   
229    // pushing event to queue
230    this->incomingEventsMutex_->lock();
231    this->incomingEvents_.push_back(inEvent);
232    this->incomingEventsMutex_->unlock();
233  }
234 
[11829]235  /**
236   * Send an event.
237   * @param event The event to send
238   */
[8327]239  void Connection::processOutgoingEvent(outgoingEvent& event)
240  {
241    ENetPeer* peer;
[11829]242    switch(event.type)
[8327]243    {
[11071]244      case OutgoingEventType::sendPacket:
[8327]245        // check whether the peer is still/already in the peer list
[11829]246        if(this->peerMap_.find(event.peerID) != this->peerMap_.end())
[8327]247        {
248          peer = this->peerMap_[event.peerID];
[11829]249          enet_peer_send(peer, event.channelID, event.packet);
[8327]250        }
251        else
252        {
253          // peer probably already disconnected so just discard packet
[11829]254          assert(event.peerID < this->nextPeerID_);
[8327]255          enet_packet_destroy(event.packet);
256        }
257        break;
[11071]258      case OutgoingEventType::disconnectPeer:
[11829]259        if(this->peerMap_.find(event.peerID) != this->peerMap_.end())
[8327]260        {
261          peer = this->peerMap_[event.peerID];
262          enet_peer_disconnect(peer, 0);
263        }
264        else
265        {
266          // peer probably already disconnected so just discard disconnect event
[11829]267          assert(event.peerID < this->nextPeerID_);
[8327]268        }
269        break;
[11071]270      case OutgoingEventType::disconnectPeers:
[11829]271        this->disconnectPeersInternal();
[8327]272        break;
[11071]273      case OutgoingEventType::broadcastPacket:
[8327]274        enet_host_broadcast( this->host_, event.channelID, event.packet );
275        break;
276      default:
277        assert(0);
278    }
279  }
[3214]280
[8327]281  void Connection::disconnectPeersInternal()
282  {
[11071]283    for( const auto& mapEntry : this->peerMap_ )
[8327]284    {
[11071]285      enet_peer_disconnect(mapEntry.second, 0);
[8327]286    }
[11829]287    uint32_t iterations = NETWORK_DISCONNECT_TIMEOUT / NETWORK_WAIT_TIMEOUT;
[8327]288    uint32_t i = 0;
289    while( this->peerMap_.size() && i++ < iterations )
290    {
291      ENetEvent event;
292      if( enet_host_service( this->host_, &event, NETWORK_WAIT_TIMEOUT ) > 0 )
293      {
294        processIncomingEvent(event);
295      }
296    }
297  }
298
[7801]299  void Connection::processQueue()
300  {
[8327]301    incomingEvent inEvent;
[6417]302
[7801]303    this->incomingEventsMutex_->lock();
304    uint32_t incomingEventsCount = this->incomingEvents_.size();
305    this->incomingEventsMutex_->unlock();
306    while( incomingEventsCount > 0 )
[3214]307    {
[8327]308      // pop event from queue
[7801]309      this->incomingEventsMutex_->lock();
[8327]310      inEvent = this->incomingEvents_.front();
[7801]311      this->incomingEvents_.pop_front();
312      this->incomingEventsMutex_->unlock();
313     
[8327]314      // process event
315      switch( inEvent.type )
[7801]316      {
[11071]317        case IncomingEventType::peerConnect:
[8327]318          addPeer(inEvent.peerID);
[3214]319          break;
[11071]320        case IncomingEventType::peerDisconnect:
[8327]321          removePeer(inEvent.peerID);
[3214]322          break;
[11071]323        case IncomingEventType::receivePacket:
[8327]324          processPacket(inEvent.packet);
[3214]325          break;
[8327]326        default:
[3214]327          break;
328      }
[7801]329     
[8327]330      // check whether there are still events in the queue
[7801]331      this->incomingEventsMutex_->lock();
332      incomingEventsCount = this->incomingEvents_.size();
333      this->incomingEventsMutex_->unlock();
[3214]334    }
335  }
[8327]336 
337  void Connection::waitOutgoingQueue()
338  {
339    uint32_t outgoingEventsCount;
340    this->outgoingEventsMutex_->lock();
341    outgoingEventsCount = this->outgoingEvents_.size();
342    this->outgoingEventsMutex_->unlock();
343    while( outgoingEventsCount )
344    {
345      msleep(1);
346      this->outgoingEventsMutex_->lock();
347      outgoingEventsCount = this->outgoingEvents_.size();
348      this->outgoingEventsMutex_->unlock();
349    }
350  }
[3214]351
[8327]352
353  incomingEvent Connection::preprocessConnectEvent(ENetEvent& event)
[7801]354  {
[8327]355    // make sure this peer doesn't exist
356    assert( this->peerMap_.find(this->nextPeerID_) == this->peerMap_.end() );
357    assert( this->peerIDMap_.find(event.peer) == this->peerIDMap_.end() );
358   
359    // give peer a new id and increase peerID for next peer
360    uint32_t peerID = this->nextPeerID_;
361    ++this->nextPeerID_;
362   
363    // add peer/peerID into peerMap_ and peerIDMap_
364    this->peerMap_[peerID] = event.peer;
365    this->peerIDMap_[event.peer] = peerID;
366   
367    // create new peerEvent and return it
[11071]368    incomingEvent inEvent = { peerID, IncomingEventType::peerConnect, nullptr };
[8327]369    return inEvent;
[3214]370  }
[7801]371 
[8327]372  incomingEvent Connection::preprocessDisconnectEvent(ENetEvent& event)
373  {
374    // assert that the peer exists and get peerID
375    assert( this->peerIDMap_.find(event.peer) != this->peerIDMap_.end() );
376    uint32_t peerID = this->peerIDMap_[event.peer];
377   
378    // remove peer/peerID from maps
379    this->peerIDMap_.erase(this->peerIDMap_.find(event.peer));
380    this->peerMap_.erase(this->peerMap_.find(peerID));
381   
382    // create new peerEvent and return it
[11071]383    incomingEvent inEvent = { peerID, IncomingEventType::peerDisconnect, nullptr };
[8327]384    return inEvent;
385  }
386 
387  incomingEvent Connection::preprocessReceiveEvent(ENetEvent& event)
388  {
389    // assert that the peer exists and get peerID
390    assert( this->peerIDMap_.find(event.peer) != this->peerIDMap_.end() );
391    uint32_t peerID = this->peerIDMap_[event.peer];
392   
393    // create new Packet from ENetPacket
394    packet::Packet* p = packet::Packet::createPacket(event.packet, peerID);
395   
396    // create new peerEvent and return it
[11071]397    incomingEvent inEvent = { peerID, IncomingEventType::receivePacket, p };
[8327]398    return inEvent;
399  }
400
401 
[7801]402  void Connection::enableCompression()
403  {
404    enet_host_compress_with_range_coder( this->host_ );
405  }
[3214]406
[7801]407
[3214]408}
Note: See TracBrowser for help on using the repository browser.