Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2118 was 2087, checked in by landauf, 16 years ago

merged objecthierarchy branch back to trunk

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