Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 3162 was 3093, checked in by scheusso, 16 years ago

it is now possible to send packets/network function calls to all clients by passing CLIENTID_UNKNOWN as clientID

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