Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/network/ConnectionManager.cc @ 1666

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

a hole lot of changes:

  • changes in structure concerning client/server (they inherit from Host now)
  • some small changes in spaceship
  • delete unused files
  • modified clientinformation (is a singleton now)
  • modified gamestatemanager (adopted clientinformation changes)
  • modified connectionmanager (adopted CI changes, is a singleton now)
  • Property svn:eol-style set to native
File size: 12.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
40#include <iostream>
[1666]41#include <assert.h>
[1282]42// boost.thread library for multithreading support
43#include <boost/bind.hpp>
44
45#include "core/CoreIncludes.h"
46#include "core/BaseObject.h"
[1502]47#include "objects/SpaceShip.h"
[1282]48#include "util/Math.h"
[1502]49#include "util/Sleep.h"
[1282]50#include "ClientInformation.h"
51#include "ConnectionManager.h"
52#include "Synchronisable.h"
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
64namespace network
65{
66  //boost::thread_group network_threads;
67 
[1666]68  ConnectionManager *ConnectionManager::instance_=0;
[1282]69 
[1666]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  }
[1666]77  boost::recursive_mutex ConnectionManager::enet_mutex_;
[1502]78 
[1666]79//   ConnectionManager::ConnectionManager(ClientInformation *head) : receiverThread_(0) {
80//     assert(instance_==0);
81//     instance_=this;
82//     quit=false;
83//     bindAddress.host = ENET_HOST_ANY;
84//     bindAddress.port = NETWORK_PORT;
85//   }
86 
87  ConnectionManager::ConnectionManager(int port){
88    assert(instance_==0);
89    instance_=this;
[1502]90    quit=false;
91    bindAddress.host = ENET_HOST_ANY;
92    bindAddress.port = port;
93  }
[1282]94
[1666]95  ConnectionManager::ConnectionManager(int port, std::string address) :receiverThread_(0) {
96    assert(instance_==0);
97    instance_=this;
[1282]98    quit=false;
99    enet_address_set_host (& bindAddress, address.c_str());
100    bindAddress.port = NETWORK_PORT;
101  }
102
[1666]103  ConnectionManager::ConnectionManager(int port, const char *address) : receiverThread_(0) {
104    assert(instance_==0);
105    instance_=this;
[1282]106    quit=false;
107    enet_address_set_host (& bindAddress, address);
108    bindAddress.port = NETWORK_PORT;
109  }
[1666]110 
111  ConnectionManager::~ConnectionManager(){
112    instance_=0;
113    if(!quit)
114      quitListener();
115  }
[1282]116
[1502]117  /*ENetPacket *ConnectionManager::getPacket(ENetAddress &address) {
[1282]118    if(!buffer.isEmpty())
119      return buffer.pop(address);
120    else
121      return NULL;
[1502]122  }*/
[1282]123/**
124This function only pops the first element in PacketBuffer (first in first out)
125used by processQueue in Server.cc
126*/
[1502]127  /*ENetPacket *ConnectionManager::getPacket(int &clientID) {
[1282]128    ENetAddress address;
129    ENetPacket *packet=getPacket(address);
130    ClientInformation *temp =head_->findClient(&address);
[1360]131    if(!temp)
132      return NULL;
[1282]133    clientID=temp->getID();
134    return packet;
[1502]135  }*/
136 
137  ENetEvent *ConnectionManager::getEvent(){
138    if(!buffer.isEmpty())
139      return buffer.pop();
140    else
141      return NULL;
[1282]142  }
143
144  bool ConnectionManager::queueEmpty() {
145    return buffer.isEmpty();
146  }
147
148  void ConnectionManager::createListener() {
149    receiverThread_ = new boost::thread(boost::bind(&ConnectionManager::receiverThread, this));
150    //network_threads.create_thread(boost::bind(boost::mem_fn(&ConnectionManager::receiverThread), this));
151         //boost::thread thr(boost::bind(boost::mem_fn(&ConnectionManager::receiverThread), this));
152    return;
153  }
154
155  bool ConnectionManager::quitListener() {
156    quit=true;
157    //network_threads.join_all();
158    receiverThread_->join();
159    return true;
160  }
[1666]161 
162//   bool ConnectionManager::addPacket(Packet::Packet *packet){
163//     ClientInformation *temp = instance_->head_->findClient(packet->getClientID());
164//     if(!temp){
165//       COUT(3) << "C.Man: addPacket findClient failed" << std::endl;
166//       return false;
167//     }
168//     ENetPacket *packet = new ENetPacket;
169//     //  TODO: finish implementation
170//   }
171//   
172 
[1282]173  bool ConnectionManager::addPacket(ENetPacket *packet, ENetPeer *peer) {
[1666]174    boost::recursive_mutex::scoped_lock lock(instance_->enet_mutex_);
175    if(enet_peer_send(peer, NETWORK_DEFAULT_CHANNEL, packet)!=0)
[1282]176      return false;
177    return true;
178  }
179
180  bool ConnectionManager::addPacket(ENetPacket *packet, int clientID) {
[1666]181    ClientInformation *temp = ClientInformation::findClient(clientID);
[1502]182    if(!temp){
183      COUT(3) << "C.Man: addPacket findClient failed" << std::endl;
[1282]184      return false;
[1502]185    }
[1666]186    return addPacket(packet, temp->getPeer());
[1282]187  }
188
189  bool ConnectionManager::addPacketAll(ENetPacket *packet) {
[1666]190    if(!instance_)
191      return false;
192    boost::recursive_mutex::scoped_lock lock(instance_->enet_mutex_);
193    for(ClientInformation *i=ClientInformation::getBegin()->next(); i!=0; i=i->next()){
[1534]194      COUT(3) << "adding broadcast packet for client: " << i->getID() << std::endl;
195      if(enet_peer_send(i->getPeer(), 0, packet)!=0)
[1282]196        return false;
197    }
198    return true;
199  }
200
[1502]201  // we actually dont need that function, because host_service does that for us
[1282]202  bool ConnectionManager::sendPackets() {
[1666]203    if(server==NULL || !instance_)
[1282]204      return false;
[1502]205    boost::recursive_mutex::scoped_lock lock(enet_mutex_);
206    enet_host_flush(server);
207    lock.unlock();
208    return true;
[1282]209  }
210
211  void ConnectionManager::receiverThread() {
212    // what about some error-handling here ?
[1502]213    ENetEvent *event;
[1282]214    atexit(enet_deinitialize);
[1502]215    { //scope of the mutex
216      boost::recursive_mutex::scoped_lock lock(enet_mutex_);
217      enet_initialize();
218      server = enet_host_create(&bindAddress, NETWORK_MAX_CONNECTIONS, 0, 0);
219      lock.unlock();
220    }
[1282]221    if(server==NULL){
222      // add some error handling here ==========================
223      quit=true;
224      return;
225    }
226
[1502]227    event = new ENetEvent;
[1282]228    while(!quit){
[1502]229      { //mutex scope
230        boost::recursive_mutex::scoped_lock lock(enet_mutex_);
231        if(enet_host_service(server, event, NETWORK_WAIT_TIMEOUT)<0){
232          // we should never reach this point
233          quit=true;
234          continue;
235          // add some error handling here ========================
236        }
237        lock.unlock();
[1282]238      }
239      switch(event->type){
240        // log handling ================
241        case ENET_EVENT_TYPE_CONNECT:
[1502]242          COUT(3) << "adding event_type_connect to queue" << std::endl;
243        case ENET_EVENT_TYPE_DISCONNECT:
244          //addClient(event);
[1282]245          //this is a workaround to ensure thread safety
[1502]246          //COUT(5) << "Con.Man: connection event has occured" << std::endl;
247          //break;
[1282]248        case ENET_EVENT_TYPE_RECEIVE:
249          //std::cout << "received data" << std::endl;
250          COUT(5) << "Con.Man: receive event has occured" << std::endl;
251          // only add, if client has connected yet and not been disconnected
[1502]252          //if(head_->findClient(&event->peer->address))
[1282]253            processData(event);
[1502]254            event = new ENetEvent;
255//           else
256//             COUT(3) << "received a packet from a client we don't know" << std::endl;
[1282]257          break;
[1502]258        //case ENET_EVENT_TYPE_DISCONNECT:
259          //clientDisconnect(event->peer);
260          //break;
[1282]261        case ENET_EVENT_TYPE_NONE:
[1502]262          //receiverThread_->yield();
263          usleep(1000);
[1282]264          break;
265      }
266//       usleep(100);
[1502]267      //receiverThread_->yield(); //TODO: find apropriate
[1282]268    }
269    disconnectClients();
270    // if we're finishied, destroy server
[1502]271    {
272      boost::recursive_mutex::scoped_lock lock(enet_mutex_);
273      enet_host_destroy(server);
274      lock.unlock();
275    }
[1282]276  }
277 
278  //### added some bugfixes here, but we cannot test them because
279  //### the server crashes everytime because of some gamestates
280  //### (trying to resolve that now)
281  void ConnectionManager::disconnectClients() {
282    ENetEvent event;
[1666]283    ClientInformation *temp = ClientInformation::getBegin()->next();
[1282]284    while(temp!=0){
[1502]285      {
286        boost::recursive_mutex::scoped_lock lock(enet_mutex_);
287        enet_peer_disconnect(temp->getPeer(), 0);
288        lock.unlock();
289      }
[1282]290      temp = temp->next();
291    }
292    //bugfix: might be the reason why server crashes when clients disconnects
[1666]293    temp = ClientInformation::getBegin()->next();
[1502]294    boost::recursive_mutex::scoped_lock lock(enet_mutex_);
295    while( temp!=0 && enet_host_service(server, &event, NETWORK_WAIT_TIMEOUT) >= 0){
[1282]296      switch (event.type)
297      {
298      case ENET_EVENT_TYPE_NONE: break;
299      case ENET_EVENT_TYPE_CONNECT: break;
300      case ENET_EVENT_TYPE_RECEIVE:
301        enet_packet_destroy(event.packet);
302        break;
303      case ENET_EVENT_TYPE_DISCONNECT:
304        COUT(4) << "disconnecting all clients" << std::endl;
[1666]305        if(ClientInformation::findClient(&(event.peer->address)))
306          delete ClientInformation::findClient(&(event.peer->address));
[1282]307        //maybe needs bugfix: might also be a reason for the server to crash
308        temp = temp->next();
309        break;
310      }
311    }
312    return;
313  }
314
315  bool ConnectionManager::processData(ENetEvent *event) {
316    // just add packet to the buffer
317    // this can be extended with some preprocessing
318    return buffer.push(event);
319  }
320
321
[1502]322
[1282]323  int ConnectionManager::getClientID(ENetPeer peer) {
324    return getClientID(peer.address);
325  }
326
327  int ConnectionManager::getClientID(ENetAddress address) {
[1666]328    return ClientInformation::findClient(&address)->getID();
[1282]329  }
330
331  ENetPeer *ConnectionManager::getClientPeer(int clientID) {
[1666]332    return ClientInformation::findClient(clientID)->getPeer();
[1282]333  }
334
335  void ConnectionManager::syncClassid(int clientID) {
[1360]336    unsigned int network_id=0, failures=0;
[1282]337    std::string classname;
338    orxonox::Identifier *id;
339    std::map<std::string, orxonox::Identifier*>::const_iterator it = orxonox::Factory::getFactoryBegin();
340    while(it != orxonox::Factory::getFactoryEnd()){
341      id = (*it).second;
342      if(id == NULL)
343        continue;
344      classname = id->getName();
345      network_id = id->getNetworkID();
[1360]346      if(network_id==0)
347        COUT(3) << "we got a null class id: " << id->getName() << std::endl;
[1282]348      COUT(4) << "Con.Man:syncClassid:\tnetwork_id: " << network_id << ", classname: " << classname << std::endl;
349
[1360]350      while(!addPacket(packet_gen.clid( (int)network_id, classname ), clientID) && failures < 10){
351        failures++;
352      }
[1282]353      ++it;
354    }
[1502]355    //sendPackets();
[1282]356    COUT(4) << "syncClassid:\tall synchClassID packets have been sent" << std::endl;
357  }
358
359 
360 
361  bool ConnectionManager::removeShip(ClientInformation *client){
362    int id=client->getShipID();
363    orxonox::Iterator<orxonox::SpaceShip> it;
364    for(it = orxonox::ObjectList<orxonox::SpaceShip>::start(); it; ++it){
365      if(it->objectID!=id)
366        continue;
367      delete *it;
368    }
369    return true;
370  }
371 
372  bool ConnectionManager::sendWelcome(int clientID, int shipID, bool allowed){
[1360]373    if(addPacket(packet_gen.generateWelcome(clientID, shipID, allowed),clientID)){
[1502]374      //sendPackets();
[1360]375      return true;
376    }else
377      return false;
[1282]378  }
379 
380  void ConnectionManager::disconnectClient(ClientInformation *client){
[1502]381    {
382      boost::recursive_mutex::scoped_lock lock(enet_mutex_);
383      enet_peer_disconnect(client->getPeer(), 0);
384      lock.unlock();
385    }
[1282]386    removeShip(client);
387  }
388 
389  bool ConnectionManager::addFakeConnectRequest(ENetEvent *ev){
390    ENetEvent event;
391    event.peer=ev->peer;
392    event.packet = packet_gen.generateConnectRequest();
393    return buffer.push(&event);
394  }
395 
396 
397
398}
Note: See TracBrowser for help on using the repository browser.