Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1494 was 1494, checked in by rgrieder, 16 years ago
  • set the svn:eol-style property to all files so, that where ever you check out, you'll get the right line endings (had to change every file with mixed endings to windows in order to set the property)
  • Property svn:eol-style set to native
File size: 15.1 KB
Line 
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"
46#include "objects/SpaceShip.h"
47#include "util/Math.h"
48#include "ClientInformation.h"
49#include "ConnectionManager.h"
50#include "Synchronisable.h"
51
52namespace std
53{
54  bool operator< (ENetAddress a, ENetAddress b) {
55    if(a.host <= b.host)
56      return true;
57    else
58      return false;
59  }
60}
61
62namespace network
63{
64  //boost::thread_group network_threads;
65 
66  ConnectionManager::ConnectionManager():receiverThread_(0){}
67  boost::recursive_mutex ConnectionManager::enet_mutex_;
68 
69  ConnectionManager::ConnectionManager(ClientInformation *head) : receiverThread_(0) {
70    quit=false;
71    bindAddress.host = ENET_HOST_ANY;
72    bindAddress.port = NETWORK_PORT;
73    head_ = head;
74  }
75 
76  ConnectionManager::ConnectionManager(ClientInformation *head, int port){
77    quit=false;
78    bindAddress.host = ENET_HOST_ANY;
79    bindAddress.port = port;
80    head_ = head;
81  }
82
83  ConnectionManager::ConnectionManager(int port, std::string address, ClientInformation *head) :receiverThread_(0) {
84    quit=false;
85    enet_address_set_host (& bindAddress, address.c_str());
86    bindAddress.port = NETWORK_PORT;
87    head_ = head;
88  }
89
90  ConnectionManager::ConnectionManager(int port, const char *address, ClientInformation *head) : receiverThread_(0) {
91    quit=false;
92    enet_address_set_host (& bindAddress, address);
93    bindAddress.port = NETWORK_PORT;
94    head_ = head;
95  }
96
97  /*ENetPacket *ConnectionManager::getPacket(ENetAddress &address) {
98    if(!buffer.isEmpty())
99      return buffer.pop(address);
100    else
101      return NULL;
102  }*/
103/**
104This function only pops the first element in PacketBuffer (first in first out)
105used by processQueue in Server.cc
106*/
107  /*ENetPacket *ConnectionManager::getPacket(int &clientID) {
108    ENetAddress address;
109    ENetPacket *packet=getPacket(address);
110    ClientInformation *temp =head_->findClient(&address);
111    if(!temp)
112      return NULL;
113    clientID=temp->getID();
114    return packet;
115  }*/
116 
117  ENetEvent *ConnectionManager::getEvent(){
118    if(!buffer.isEmpty())
119      return buffer.pop();
120    else
121      return NULL;
122  }
123
124  bool ConnectionManager::queueEmpty() {
125    return buffer.isEmpty();
126  }
127
128  void ConnectionManager::createListener() {
129    receiverThread_ = new boost::thread(boost::bind(&ConnectionManager::receiverThread, this));
130    //network_threads.create_thread(boost::bind(boost::mem_fn(&ConnectionManager::receiverThread), this));
131         //boost::thread thr(boost::bind(boost::mem_fn(&ConnectionManager::receiverThread), this));
132    return;
133  }
134
135  bool ConnectionManager::quitListener() {
136    quit=true;
137    //network_threads.join_all();
138    receiverThread_->join();
139    return true;
140  }
141
142  bool ConnectionManager::addPacket(ENetPacket *packet, ENetPeer *peer) {
143    ClientInformation *temp = head_->findClient(&(peer->address));
144    if(!temp)
145      return false;
146    boost::recursive_mutex::scoped_lock lock(enet_mutex_);
147    if(enet_peer_send(peer, (enet_uint8)temp->getID() , packet)!=0)
148      return false;
149    return true;
150  }
151
152  bool ConnectionManager::addPacket(ENetPacket *packet, int clientID) {
153    ClientInformation *temp = head_->findClient(clientID);
154    if(!temp)
155      return false;
156    boost::recursive_mutex::scoped_lock lock(enet_mutex_);
157    if(enet_peer_send(temp->getPeer(), (enet_uint8)clientID, packet)!=0)
158      return false;
159    return true;
160  }
161
162  bool ConnectionManager::addPacketAll(ENetPacket *packet) {
163    boost::recursive_mutex::scoped_lock lock(enet_mutex_);
164    for(ClientInformation *i=head_->next(); i!=0; i=i->next()){
165      if(enet_peer_send(i->getPeer(), (enet_uint8)i->getID(), packet)!=0)
166        return false;
167    }
168    return true;
169  }
170
171  bool ConnectionManager::sendPackets() {
172    if(server==NULL)
173      return false;
174    boost::recursive_mutex::scoped_lock lock(enet_mutex_);
175    enet_host_flush(server);
176    lock.unlock();
177    return true;
178  }
179
180  void ConnectionManager::receiverThread() {
181    // what about some error-handling here ?
182    ENetEvent *event;
183    atexit(enet_deinitialize);
184    { //scope of the mutex
185      boost::recursive_mutex::scoped_lock lock(enet_mutex_);
186      enet_initialize();
187      server = enet_host_create(&bindAddress, NETWORK_MAX_CONNECTIONS, 0, 0);
188      lock.unlock();
189    }
190    if(server==NULL){
191      // add some error handling here ==========================
192      quit=true;
193      return;
194    }
195
196    while(!quit){
197      event = new ENetEvent;
198      { //mutex scope
199        boost::recursive_mutex::scoped_lock lock(enet_mutex_);
200        if(enet_host_service(server, event, NETWORK_WAIT_TIMEOUT)<0){
201          // we should never reach this point
202          quit=true;
203          continue;
204          // add some error handling here ========================
205        }
206        lock.unlock();
207      }
208      switch(event->type){
209        // log handling ================
210        case ENET_EVENT_TYPE_CONNECT:
211          COUT(3) << "adding event_type_connect to queue" << std::endl;
212        case ENET_EVENT_TYPE_DISCONNECT:
213          //addClient(event);
214          //this is a workaround to ensure thread safety
215          //COUT(5) << "Con.Man: connection event has occured" << std::endl;
216          //break;
217        case ENET_EVENT_TYPE_RECEIVE:
218          //std::cout << "received data" << std::endl;
219          COUT(5) << "Con.Man: receive event has occured" << std::endl;
220          // only add, if client has connected yet and not been disconnected
221          //if(head_->findClient(&event->peer->address))
222            processData(event);
223//           else
224//             COUT(3) << "received a packet from a client we don't know" << std::endl;
225          break;
226        //case ENET_EVENT_TYPE_DISCONNECT:
227          //clientDisconnect(event->peer);
228          //break;
229        case ENET_EVENT_TYPE_NONE:
230          delete event;
231          receiverThread_->yield();
232          break;
233      }
234//       usleep(100);
235      //receiverThread_->yield(); //TODO: find apropriate
236    }
237    disconnectClients();
238    // if we're finishied, destroy server
239    {
240      boost::recursive_mutex::scoped_lock lock(enet_mutex_);
241      enet_host_destroy(server);
242      lock.unlock();
243    }
244  }
245 
246  //### added some bugfixes here, but we cannot test them because
247  //### the server crashes everytime because of some gamestates
248  //### (trying to resolve that now)
249  void ConnectionManager::disconnectClients() {
250    ENetEvent event;
251    ClientInformation *temp = head_->next();
252    while(temp!=0){
253      {
254        boost::recursive_mutex::scoped_lock lock(enet_mutex_);
255        enet_peer_disconnect(temp->getPeer(), 0);
256        lock.unlock();
257      }
258      temp = temp->next();
259    }
260    //bugfix: might be the reason why server crashes when clients disconnects
261    temp = head_->next();
262    boost::recursive_mutex::scoped_lock lock(enet_mutex_);
263    while( temp!=0 && enet_host_service(server, &event, NETWORK_WAIT_TIMEOUT) >= 0){
264      switch (event.type)
265      {
266      case ENET_EVENT_TYPE_NONE: break;
267      case ENET_EVENT_TYPE_CONNECT: break;
268      case ENET_EVENT_TYPE_RECEIVE:
269        enet_packet_destroy(event.packet);
270        break;
271      case ENET_EVENT_TYPE_DISCONNECT:
272        COUT(4) << "disconnecting all clients" << std::endl;
273        if(head_->findClient(&(event.peer->address)))
274          delete head_->findClient(&(event.peer->address));
275        //maybe needs bugfix: might also be a reason for the server to crash
276        temp = temp->next();
277        break;
278      }
279    }
280    return;
281  }
282
283  bool ConnectionManager::processData(ENetEvent *event) {
284    // just add packet to the buffer
285    // this can be extended with some preprocessing
286    return buffer.push(event);
287  }
288
289/**
290This function adds a client that connects to the clientlist of the server
291NOTE: if you change this, don't forget to change the test function
292addClientTest in diffTest.cc since addClient is not good for testing because of syncClassid
293*/
294  /*bool ConnectionManager::addClient(ENetEvent *event) {
295    ClientInformation *temp = head_->insertBack(new ClientInformation);
296    if(!temp){
297      COUT(2) << "Conn.Man. could not add client" << std::endl;
298      return false;
299    }
300    if(temp->prev()->getHead()) { //not good if you use anything else than insertBack
301      temp->prev()->setID(0); //bugfix: not necessary but usefull
302      temp->setID(1);
303    }
304    else
305      temp->setID(temp->prev()->getID()+1);
306    temp->setPeer(event->peer);
307    COUT(3) << "Con.Man: added client id: " << temp->getID() << std::endl;
308    return true;
309  }*/
310
311  int ConnectionManager::getClientID(ENetPeer peer) {
312    return getClientID(peer.address);
313  }
314
315  int ConnectionManager::getClientID(ENetAddress address) {
316    return head_->findClient(&address)->getID();
317  }
318
319  ENetPeer *ConnectionManager::getClientPeer(int clientID) {
320    return head_->findClient(clientID)->getPeer();
321  }
322
323  void ConnectionManager::syncClassid(int clientID) {
324    unsigned int network_id=0, failures=0;
325    std::string classname;
326    orxonox::Identifier *id;
327    std::map<std::string, orxonox::Identifier*>::const_iterator it = orxonox::Factory::getFactoryBegin();
328    while(it != orxonox::Factory::getFactoryEnd()){
329      id = (*it).second;
330      if(id == NULL)
331        continue;
332      classname = id->getName();
333      network_id = id->getNetworkID();
334      if(network_id==0)
335        COUT(3) << "we got a null class id: " << id->getName() << std::endl;
336      COUT(4) << "Con.Man:syncClassid:\tnetwork_id: " << network_id << ", classname: " << classname << std::endl;
337
338      while(!addPacket(packet_gen.clid( (int)network_id, classname ), clientID) && failures < 10){
339        failures++;
340      }
341      ++it;
342    }
343    sendPackets();
344    COUT(4) << "syncClassid:\tall synchClassID packets have been sent" << std::endl;
345  }
346
347  /*bool ConnectionManager::createClient(int clientID){
348    ClientInformation *temp = head_->findClient(clientID);
349    if(!temp){
350      COUT(2) << "Conn.Man. could not create client with id: " << clientID << std::endl;
351      return false;
352    }
353    COUT(4) << "Con.Man: creating client id: " << temp->getID() << std::endl;
354    syncClassid(temp->getID());
355    COUT(4) << "creating spaceship for clientid: " << temp->getID() << std::endl;
356    // TODO: this is only a hack, untill we have a possibility to define default player-join actions
357    if(!createShip(temp))
358      COUT(2) << "Con.Man. could not create ship for clientid: " << clientID << std::endl;
359    else
360      COUT(3) << "created spaceship" << std::endl;
361    temp->setSynched(true);
362    COUT(3) << "sending welcome" << std::endl;
363    sendWelcome(temp->getID(), temp->getShipID(), true);
364    return true;
365  }*/
366 
367  /*bool ConnectionManager::removeClient(int clientID){
368    boost::recursive_mutex::scoped_lock lock(head_->mutex_);
369    orxonox::Iterator<orxonox::SpaceShip> it = orxonox::ObjectList<orxonox::SpaceShip>::start();
370    ClientInformation *client = head_->findClient(clientID);
371    if(!client)
372      return false;
373    while(it){
374      if(it->objectID!=client->getShipID()){
375        ++it;
376        continue;
377      }
378      orxonox::Iterator<orxonox::SpaceShip> temp=it;
379      ++it;
380      delete  *temp;
381      return head_->removeClient(clientID);
382    }
383    return false;
384  }*/
385 
386/*  bool ConnectionManager::createShip(ClientInformation *client){
387    if(!client)
388      return false;
389    orxonox::Identifier* id = ID("SpaceShip");
390    if(!id){
391      COUT(4) << "We could not create the SpaceShip for client: " << client->getID() << std::endl;
392      return false;
393    }
394    orxonox::SpaceShip *no = dynamic_cast<orxonox::SpaceShip *>(id->fabricate());
395    no->setPosition(orxonox::Vector3(0,0,80));
396    no->setScale(10);
397    //no->setYawPitchRoll(orxonox::Degree(-90),orxonox::Degree(-90),orxonox::Degree(0));
398    no->setMesh("assff.mesh");
399    no->setMaxSpeed(500);
400    no->setMaxSideAndBackSpeed(50);
401    no->setMaxRotation(1.0);
402    no->setTransAcc(200);
403    no->setRotAcc(3.0);
404    no->setTransDamp(75);
405    no->setRotDamp(1.0);
406    no->setCamera("cam_"+client->getID());
407    no->classID = id->getNetworkID();
408    no->create();
409   
410    client->setShipID(no->objectID);
411    return true;
412  }*/
413 
414  bool ConnectionManager::removeShip(ClientInformation *client){
415    int id=client->getShipID();
416    orxonox::Iterator<orxonox::SpaceShip> it;
417    for(it = orxonox::ObjectList<orxonox::SpaceShip>::start(); it; ++it){
418      if(it->objectID!=id)
419        continue;
420      delete *it;
421    }
422    return true;
423  }
424 
425  bool ConnectionManager::sendWelcome(int clientID, int shipID, bool allowed){
426    if(addPacket(packet_gen.generateWelcome(clientID, shipID, allowed),clientID)){
427      sendPackets();
428      return true;
429    }else
430      return false;
431  }
432 
433  void ConnectionManager::disconnectClient(ClientInformation *client){
434    {
435      boost::recursive_mutex::scoped_lock lock(enet_mutex_);
436      enet_peer_disconnect(client->getPeer(), 0);
437      lock.unlock();
438    }
439    removeShip(client);
440  }
441 
442  bool ConnectionManager::addFakeConnectRequest(ENetEvent *ev){
443    ENetEvent event;
444    event.peer=ev->peer;
445    event.packet = packet_gen.generateConnectRequest();
446    return buffer.push(&event);
447  }
448 
449 
450//   int ConnectionManager::getNumberOfClients() {
451//     
452//     return clientsShip.size();
453//   }
454 
455  /*void ConnectionManager::addClientsObjectID( int clientID, int objectID ) {
456  COUT(4) << "ship of client: " << clientID << ": " << objectID << " mapped" << std::endl;
457  clientsShip.insert( std::make_pair( clientID, objectID ) );
458}
459
460  int ConnectionManager::getClientsShipID( int clientID ) {
461  return clientsShip[clientID];
462}
463
464  int ConnectionManager::getObjectsClientID( int objectID ) {
465  std::map<int, int>::iterator iter;
466  for( iter = clientsShip.begin(); iter != clientsShip.end(); iter++ ) {
467  if( iter->second == objectID ) return iter->first;
468}
469  return -99;
470}
471
472  void ConnectionManager::deleteClientIDReg( int clientID ) {
473  clientsShip.erase( clientID );
474}
475
476  void ConnectionManager::deleteObjectIDReg( int objectID ) {
477  std::map<int, int>::iterator iter = clientsShip.begin();
478  for( iter = clientsShip.begin(); iter != clientsShip.end(); iter++ ) {
479  if( iter->second == objectID ) break;
480}
481  clientsShip.erase( iter->first );
482}*/
483}
Note: See TracBrowser for help on using the repository browser.