Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1636 was 1534, checked in by rgrieder, 16 years ago

merged network branch back to trunk

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