Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

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