Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/network/ConnectionManager.cc @ 3027

Last change on this file since 3027 was 2896, checked in by landauf, 16 years ago

Merged gui branch back to trunk.

I did 2 small changes in IngameManager.cc on line 777 and 888 (yes, really), because const_reverse_iterator strangely doesn't work on MinGW.

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