Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/netp/src/network/ConnectionManager.cc @ 2961

Last change on this file since 2961 was 2794, checked in by scheusso, 16 years ago

some optimisations (mostly inlined SynchronisableVariable functions)
trying to track down a bug with enet connections

  • Property svn:eol-style set to native
File size: 8.6 KB
RevLine 
[1282]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, (C) 2007
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29//
30// C++ Interface: ConnectionManager
31//
32// Description: The Class ConnectionManager manages the servers conenctions to the clients.
33// each connection is provided by a new process. communication between master process and
34// connection processes is provided by ...
35//
36//
37// Author:  Oliver Scheuss
38//
39
[1842]40#include "ConnectionManager.h"
41
[2773]42#include <enet/enet.h>
[1282]43#include <iostream>
[2773]44#include <cassert>
[1282]45// boost.thread library for multithreading support
[1755]46#include <boost/thread/thread.hpp>
[1282]47#include <boost/bind.hpp>
[2773]48#include <boost/thread/recursive_mutex.hpp>
[1282]49
50#include "util/Math.h"
[1502]51#include "util/Sleep.h"
[1282]52#include "ClientInformation.h"
[2662]53#include "synchronisable/Synchronisable.h"
[1735]54#include "packet/ClassID.h"
[1282]55
56namespace std
57{
58  bool operator< (ENetAddress a, ENetAddress b) {
[2794]59    return a.host <= b.host;
[1282]60  }
61}
62
[2171]63namespace orxonox
[1282]64{
65  //boost::thread_group network_threads;
[2773]66  static boost::recursive_mutex enet_mutex_g;
[1747]67
[1735]68  ConnectionManager *ConnectionManager::instance_=0;
[1747]69
[1735]70  ConnectionManager::ConnectionManager():receiverThread_(0){
71    assert(instance_==0);
72    instance_=this;
[1282]73    quit=false;
[2773]74    bindAddress = new ENetAddress();
75    bindAddress->host = ENET_HOST_ANY;
76    bindAddress->port = NETWORK_PORT;
[1282]77  }
[1747]78
[1735]79  ConnectionManager::ConnectionManager(int port){
80    assert(instance_==0);
81    instance_=this;
[1502]82    quit=false;
[2773]83    bindAddress = new ENetAddress();
84    bindAddress->host = ENET_HOST_ANY;
85    bindAddress->port = port;
[1502]86  }
[1282]87
[2087]88  ConnectionManager::ConnectionManager(int port, const std::string& address) :receiverThread_(0) {
[1735]89    assert(instance_==0);
90    instance_=this;
[1282]91    quit=false;
[2773]92    bindAddress = new ENetAddress();
93    enet_address_set_host (bindAddress, address.c_str());
94    bindAddress->port = NETWORK_PORT;
[1282]95  }
96
[1735]97  ConnectionManager::ConnectionManager(int port, const char *address) : receiverThread_(0) {
98    assert(instance_==0);
99    instance_=this;
[1282]100    quit=false;
[2773]101    bindAddress = new ENetAddress();
102    enet_address_set_host (bindAddress, address);
103    bindAddress->port = NETWORK_PORT;
[1282]104  }
[1747]105
[1735]106  ConnectionManager::~ConnectionManager(){
107    if(!quit)
108      quitListener();
[1907]109    instance_=0;
[2773]110    delete bindAddress;
[1735]111  }
[1282]112
[1747]113
[1502]114  ENetEvent *ConnectionManager::getEvent(){
115    if(!buffer.isEmpty())
116      return buffer.pop();
117    else
118      return NULL;
[1282]119  }
120
121  bool ConnectionManager::queueEmpty() {
122    return buffer.isEmpty();
123  }
124
125  void ConnectionManager::createListener() {
126    receiverThread_ = new boost::thread(boost::bind(&ConnectionManager::receiverThread, this));
127    return;
128  }
129
130  bool ConnectionManager::quitListener() {
131    quit=true;
132    receiverThread_->join();
133    return true;
134  }
[1747]135
136
[1282]137  bool ConnectionManager::addPacket(ENetPacket *packet, ENetPeer *peer) {
[2773]138    boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
[1735]139    if(enet_peer_send(peer, NETWORK_DEFAULT_CHANNEL, packet)!=0)
[1282]140      return false;
141    return true;
142  }
143
144  bool ConnectionManager::addPacket(ENetPacket *packet, int clientID) {
[1735]145    ClientInformation *temp = ClientInformation::findClient(clientID);
[1502]146    if(!temp){
147      COUT(3) << "C.Man: addPacket findClient failed" << std::endl;
[1282]148      return false;
[1502]149    }
[1735]150    return addPacket(packet, temp->getPeer());
[1282]151  }
152
153  bool ConnectionManager::addPacketAll(ENetPacket *packet) {
[1735]154    if(!instance_)
155      return false;
[2773]156    boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
[1735]157    for(ClientInformation *i=ClientInformation::getBegin()->next(); i!=0; i=i->next()){
[1534]158      COUT(3) << "adding broadcast packet for client: " << i->getID() << std::endl;
159      if(enet_peer_send(i->getPeer(), 0, packet)!=0)
[1282]160        return false;
161    }
162    return true;
163  }
164
[1502]165  // we actually dont need that function, because host_service does that for us
[1282]166  bool ConnectionManager::sendPackets() {
[1735]167    if(server==NULL || !instance_)
[1282]168      return false;
[2773]169    boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
[1502]170    enet_host_flush(server);
171    lock.unlock();
172    return true;
[1282]173  }
174
175  void ConnectionManager::receiverThread() {
176    // what about some error-handling here ?
[1502]177    ENetEvent *event;
[1282]178    atexit(enet_deinitialize);
[1502]179    { //scope of the mutex
[2773]180      boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
[1502]181      enet_initialize();
[2773]182      server = enet_host_create(bindAddress, NETWORK_MAX_CONNECTIONS, 0, 0);
[1502]183      lock.unlock();
184    }
[1282]185    if(server==NULL){
186      // add some error handling here ==========================
187      quit=true;
188      return;
189    }
190
[1502]191    event = new ENetEvent;
[1282]192    while(!quit){
[1502]193      { //mutex scope
[2773]194        boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
[1502]195        if(enet_host_service(server, event, NETWORK_WAIT_TIMEOUT)<0){
196          // we should never reach this point
[2794]197          assert(0);
[1502]198          quit=true;
199          continue;
200          // add some error handling here ========================
201        }
202        lock.unlock();
[1282]203      }
204      switch(event->type){
205        // log handling ================
206        case ENET_EVENT_TYPE_CONNECT:
[1502]207        case ENET_EVENT_TYPE_DISCONNECT:
[1282]208        case ENET_EVENT_TYPE_RECEIVE:
209            processData(event);
[1502]210            event = new ENetEvent;
[1282]211          break;
212        case ENET_EVENT_TYPE_NONE:
[1502]213          //receiverThread_->yield();
[2794]214          msleep(10);
[1282]215          break;
216      }
217//       usleep(100);
[1502]218      //receiverThread_->yield(); //TODO: find apropriate
[1282]219    }
220    disconnectClients();
221    // if we're finishied, destroy server
[1502]222    {
[2773]223      boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
[1502]224      enet_host_destroy(server);
225      lock.unlock();
226    }
[1282]227  }
[1747]228
[1282]229  //### added some bugfixes here, but we cannot test them because
230  //### the server crashes everytime because of some gamestates
231  //### (trying to resolve that now)
232  void ConnectionManager::disconnectClients() {
233    ENetEvent event;
[1735]234    ClientInformation *temp = ClientInformation::getBegin()->next();
[1282]235    while(temp!=0){
[1502]236      {
[2773]237        boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
[1502]238        enet_peer_disconnect(temp->getPeer(), 0);
239        lock.unlock();
240      }
[1282]241      temp = temp->next();
242    }
243    //bugfix: might be the reason why server crashes when clients disconnects
[1735]244    temp = ClientInformation::getBegin()->next();
[2773]245    boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
[1502]246    while( temp!=0 && enet_host_service(server, &event, NETWORK_WAIT_TIMEOUT) >= 0){
[1282]247      switch (event.type)
248      {
249      case ENET_EVENT_TYPE_NONE: break;
250      case ENET_EVENT_TYPE_CONNECT: break;
251      case ENET_EVENT_TYPE_RECEIVE:
252        enet_packet_destroy(event.packet);
253        break;
254      case ENET_EVENT_TYPE_DISCONNECT:
255        COUT(4) << "disconnecting all clients" << std::endl;
[1735]256        if(ClientInformation::findClient(&(event.peer->address)))
257          delete ClientInformation::findClient(&(event.peer->address));
[1282]258        //maybe needs bugfix: might also be a reason for the server to crash
259        temp = temp->next();
260        break;
261      }
262    }
263    return;
264  }
265
266
[2773]267  int ConnectionManager::getClientID(ENetPeer* peer) {
268    return getClientID(&(peer->address));
[1282]269  }
270
[2773]271  int ConnectionManager::getClientID(ENetAddress* address) {
272    return ClientInformation::findClient(address)->getID();
[1282]273  }
274
275  ENetPeer *ConnectionManager::getClientPeer(int clientID) {
[1735]276    return ClientInformation::findClient(clientID)->getPeer();
[1282]277  }
278
[2759]279
[1735]280  void ConnectionManager::syncClassid(unsigned int clientID) {
[2759]281    int failures=0;
282    packet::ClassID *classid = new packet::ClassID();
283    classid->setClientID(clientID);
284    while(!classid->send() && failures < 10){
285      failures++;
[1282]286    }
[2759]287    assert(failures<10);
[1282]288    COUT(4) << "syncClassid:\tall synchClassID packets have been sent" << std::endl;
289  }
[2759]290 
[1282]291
292  void ConnectionManager::disconnectClient(ClientInformation *client){
[1502]293    {
[2773]294      boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
[1502]295      enet_peer_disconnect(client->getPeer(), 0);
296      lock.unlock();
297    }
[1282]298  }
299
[1747]300
[1282]301}
Note: See TracBrowser for help on using the repository browser.