Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/PresentationFS18/src/libraries/network/Connection.cc @ 12020

Last change on this file since 12020 was 12020, checked in by patricwi, 6 years ago

Merged Masterserver

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