Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

merged network branch back to trunk

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