Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network6/src/libraries/network/Connection.cc @ 7825

Last change on this file since 7825 was 7825, checked in by scheusso, 13 years ago

-enabling client-side gamestate diffing
-added some optimisations

  • Property svn:eol-style set to native
File size: 9.5 KB
Line 
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>
32#include <deque>
33#define WIN32_LEAN_AND_MEAN
34#include <enet/enet.h>
35#include <boost/thread.hpp>
36#include <boost/thread/mutex.hpp>
37#include <boost/date_time.hpp>
38
39#include "packet/Packet.h"
40
41namespace orxonox
42{
43  const boost::posix_time::millisec NETWORK_COMMUNICATION_THREAD_WAIT_TIME(20);
44
45  Connection::Connection(uint32_t firstPeerID):
46    host_(0), bCommunicationThreadRunning_(false), nextPeerID_(firstPeerID)
47  {
48    enet_initialize();
49    atexit(enet_deinitialize);
50    this->incomingEventsMutex_ = new boost::mutex;
51    this->outgoingEventsMutex_ = new boost::mutex;
52  }
53
54  Connection::~Connection()
55  {
56    delete this->incomingEventsMutex_;
57    delete this->outgoingEventsMutex_;
58  }
59
60  void Connection::startCommunicationThread()
61  {
62    this->bCommunicationThreadRunning_ = true;
63    this->communicationThread_ = new boost::thread(&Connection::communicationThread, this);
64  }
65 
66  void Connection::stopCommunicationThread()
67  {
68    this->bCommunicationThreadRunning_ = false;
69    if( !this->communicationThread_->timed_join(NETWORK_COMMUNICATION_THREAD_WAIT_TIME) )
70    {
71      // force thread to stop
72      this->communicationThread_->interrupt();
73    }
74    delete this->communicationThread_;
75  }
76
77  void Connection::disconnectPeer(uint32_t peerID)
78  {
79    outgoingEvent outEvent = { peerID, outgoingEventType::disconnectPeer, 0, 0 };
80   
81    this->outgoingEventsMutex_->lock();
82    this->outgoingEvents_.push_back(outEvent);
83    this->outgoingEventsMutex_->unlock();
84  }
85 
86  void Connection::disconnectPeers()
87  {
88    outgoingEvent outEvent = { 0, outgoingEventType::disconnectPeers, 0, 0 };
89   
90    this->outgoingEventsMutex_->lock();
91    this->outgoingEvents_.push_back(outEvent);
92    this->outgoingEventsMutex_->unlock();
93  }
94
95  void Connection::addPacket(ENetPacket* packet, uint32_t peerID, uint8_t channelID)
96  {
97    outgoingEvent outEvent = { peerID, outgoingEventType::sendPacket, packet, channelID };
98   
99    this->outgoingEventsMutex_->lock();
100    this->outgoingEvents_.push_back(outEvent);
101    this->outgoingEventsMutex_->unlock();
102  }
103 
104  void Connection::broadcastPacket(ENetPacket* packet, uint8_t channelID)
105  {
106    outgoingEvent outEvent = { 0, outgoingEventType::broadcastPacket, packet, channelID };
107   
108    this->outgoingEventsMutex_->lock();
109    this->outgoingEvents_.push_back(outEvent);
110    this->outgoingEventsMutex_->unlock();
111  }
112
113 
114  void Connection::communicationThread()
115  {
116    ENetEvent event;
117   
118    while( bCommunicationThreadRunning_ )
119    {
120      // Receive all pending incoming Events (such as packets, connects and disconnects)
121      while( enet_host_check_events( this->host_, &event ) > 0 )
122      {
123        processIncomingEvent(event);
124      }
125     
126      // Send all waiting outgoing packets
127      this->outgoingEventsMutex_->lock();
128      uint32_t outgoingEventsCount = this->outgoingEvents_.size();
129      this->outgoingEventsMutex_->unlock();
130      while( outgoingEventsCount > 0 )
131      {
132//         COUT(0) << "outgoing event" << endl;
133        this->outgoingEventsMutex_->lock();
134        outgoingEvent outEvent = this->outgoingEvents_.front();
135        this->outgoingEvents_.pop_front();
136        this->outgoingEventsMutex_->unlock();
137       
138        processOutgoingEvent(outEvent);
139       
140        this->outgoingEventsMutex_->lock();
141        outgoingEventsCount = this->outgoingEvents_.size();
142        this->outgoingEventsMutex_->unlock();
143      }
144     
145      // Wait for incoming events (at most NETWORK_WAIT_TIMEOUT ms)
146      if( enet_host_service( this->host_, &event, NETWORK_WAIT_TIMEOUT ) > 0 )
147      {
148        processIncomingEvent(event);
149      }
150    }
151  }
152 
153  void Connection::processIncomingEvent(ENetEvent& event)
154  {
155    incomingEvent inEvent;
156    // preprocess event
157    switch( event.type )
158    {
159      case ENET_EVENT_TYPE_CONNECT:
160        inEvent = preprocessConnectEvent(event);
161        break;
162      case ENET_EVENT_TYPE_RECEIVE:
163        inEvent = preprocessReceiveEvent(event);
164        break;
165      case ENET_EVENT_TYPE_DISCONNECT:
166        inEvent = preprocessDisconnectEvent(event);
167        break;
168      case ENET_EVENT_TYPE_NONE:
169      default:
170        return;
171    }
172   
173    // pushing event to queue
174    this->incomingEventsMutex_->lock();
175    this->incomingEvents_.push_back(inEvent);
176    this->incomingEventsMutex_->unlock();
177  }
178 
179  void Connection::processOutgoingEvent(outgoingEvent& event)
180  {
181    ENetPeer* peer;
182    switch( event.type )
183    {
184      case outgoingEventType::sendPacket:
185        // check whether the peer is still/already in the peer list
186        if( this->peerMap_.find(event.peerID) != this->peerMap_.end() )
187        {
188          peer = this->peerMap_[event.peerID];
189          enet_peer_send( peer, event.channelID, event.packet );
190        }
191        else
192        {
193          // peer probably already disconnected so just discard packet
194          assert(event.peerID<this->nextPeerID_);
195          delete event.packet;
196        }
197        break;
198      case outgoingEventType::disconnectPeer:
199        if( this->peerMap_.find(event.peerID) != this->peerMap_.end() )
200        {
201          peer = this->peerMap_[event.peerID];
202          enet_peer_disconnect(peer, 0);
203        }
204        else
205        {
206          // peer probably already disconnected so just discard disconnect event
207          assert(event.peerID<this->nextPeerID_);
208        }
209        break;
210      case outgoingEventType::disconnectPeers:
211        while( this->peerMap_.size()!=0 )
212        {
213          peer = this->peerMap_.begin()->second;
214          enet_peer_disconnect(peer, 0);
215        }
216        break;
217      case outgoingEventType::broadcastPacket:
218        enet_host_broadcast( this->host_, event.channelID, event.packet );
219        break;
220      default:
221        assert(0);
222    }
223  }
224
225
226  void Connection::processQueue()
227  {
228    incomingEvent inEvent;
229
230    this->incomingEventsMutex_->lock();
231    uint32_t incomingEventsCount = this->incomingEvents_.size();
232    this->incomingEventsMutex_->unlock();
233    while( incomingEventsCount > 0 )
234    {
235      // pop event from queue
236      this->incomingEventsMutex_->lock();
237      inEvent = this->incomingEvents_.front();
238      this->incomingEvents_.pop_front();
239      this->incomingEventsMutex_->unlock();
240     
241      // process event
242      switch( inEvent.type )
243      {
244        case incomingEventType::peerConnect:
245          addPeer(inEvent.peerID);
246          break;
247        case incomingEventType::peerDisconnect:
248          removePeer(inEvent.peerID);
249          break;
250        case incomingEventType::receivePacket:
251          processPacket(inEvent.packet);
252          break;
253        default:
254          break;
255      }
256     
257      // check whether there are still events in the queue
258      this->incomingEventsMutex_->lock();
259      incomingEventsCount = this->incomingEvents_.size();
260      this->incomingEventsMutex_->unlock();
261    }
262  }
263
264  incomingEvent Connection::preprocessConnectEvent(ENetEvent& event)
265  {
266    // make sure this peer doesn't exist
267    assert( this->peerMap_.find(this->nextPeerID_) == this->peerMap_.end() );
268    assert( this->peerIDMap_.find(event.peer) == this->peerIDMap_.end() );
269   
270    // give peer a new id and increase peerID for next peer
271    uint32_t peerID = this->nextPeerID_;
272    ++this->nextPeerID_;
273   
274    // add peer/peerID into peerMap_ and peerIDMap_
275    this->peerMap_[peerID] = event.peer;
276    this->peerIDMap_[event.peer] = peerID;
277   
278    // create new peerEvent and return it
279    incomingEvent inEvent = { peerID, incomingEventType::peerConnect, 0 };
280    return inEvent;
281  }
282 
283  incomingEvent Connection::preprocessDisconnectEvent(ENetEvent& event)
284  {
285    // assert that the peer exists and get peerID
286    assert( this->peerIDMap_.find(event.peer) != this->peerIDMap_.end() );
287    uint32_t peerID = this->peerIDMap_[event.peer];
288   
289    // remove peer/peerID from maps
290    this->peerIDMap_.erase(this->peerIDMap_.find(event.peer));
291    this->peerMap_.erase(this->peerMap_.find(peerID));
292   
293    // create new peerEvent and return it
294    incomingEvent inEvent = { peerID, incomingEventType::peerDisconnect, 0 };
295    return inEvent;
296  }
297 
298  incomingEvent Connection::preprocessReceiveEvent(ENetEvent& event)
299  {
300    // assert that the peer exists and get peerID
301    assert( this->peerIDMap_.find(event.peer) != this->peerIDMap_.end() );
302    uint32_t peerID = this->peerIDMap_[event.peer];
303   
304    // create new Packet from ENetPacket
305    packet::Packet* p = packet::Packet::createPacket(event.packet, peerID);
306   
307    // create new peerEvent and return it
308    incomingEvent inEvent = { peerID, incomingEventType::receivePacket, p };
309    return inEvent;
310  }
311
312 
313  void Connection::enableCompression()
314  {
315    enet_host_compress_with_range_coder( this->host_ );
316  }
317
318
319}
Note: See TracBrowser for help on using the repository browser.