Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1747 was 1747, checked in by landauf, 16 years ago

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