Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2770 was 2759, checked in by scheusso, 16 years ago

merged network branch (windows,multiplayer fixes) back to trunk

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