Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/orxonox_tutorial/src/network/ConnectionManager.cc @ 1846

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

Merged Revisions 1831 - 1845 to tutorial. This is an update from the trunk.

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