Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Fix in Projectiles (network fix)
different improvements in synchronisable and gamestates

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