Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/questsystem5/src/network/ConnectionManager.cc @ 2948

Last change on this file since 2948 was 2908, checked in by dafrick, 16 years ago

Reverted to revision 2906 (because I'm too stupid to merge correctly, 2nd try will follow shortly. ;))

  • Property svn:eol-style set to native
File size: 8.8 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 <enet/enet.h>
43#include <iostream>
44#include <cassert>
45// boost.thread library for multithreading support
46#include <boost/thread/thread.hpp>
47#include <boost/bind.hpp>
48#include <boost/thread/recursive_mutex.hpp>
49
50#include "util/Math.h"
51#include "util/Sleep.h"
52#include "ClientInformation.h"
53#include "synchronisable/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 orxonox
67{
68  //boost::thread_group network_threads;
69  static boost::recursive_mutex enet_mutex_g;
70
71  ConnectionManager *ConnectionManager::instance_=0;
72
73  ConnectionManager::ConnectionManager():receiverThread_(0){
74    assert(instance_==0);
75    instance_=this;
76    quit=false;
77    bindAddress = new ENetAddress();
78    bindAddress->host = ENET_HOST_ANY;
79    bindAddress->port = NETWORK_PORT;
80  }
81
82  ConnectionManager::ConnectionManager(int port){
83    assert(instance_==0);
84    instance_=this;
85    quit=false;
86    bindAddress = new ENetAddress();
87    bindAddress->host = ENET_HOST_ANY;
88    bindAddress->port = port;
89  }
90
91  ConnectionManager::ConnectionManager(int port, const std::string& address) :receiverThread_(0) {
92    assert(instance_==0);
93    instance_=this;
94    quit=false;
95    bindAddress = new ENetAddress();
96    enet_address_set_host (bindAddress, address.c_str());
97    bindAddress->port = NETWORK_PORT;
98  }
99
100  ConnectionManager::ConnectionManager(int port, const char *address) : receiverThread_(0) {
101    assert(instance_==0);
102    instance_=this;
103    quit=false;
104    bindAddress = new ENetAddress();
105    enet_address_set_host (bindAddress, address);
106    bindAddress->port = NETWORK_PORT;
107  }
108
109  ConnectionManager::~ConnectionManager(){
110    if(!quit)
111      quitListener();
112    instance_=0;
113    delete bindAddress;
114  }
115
116
117  ENetEvent *ConnectionManager::getEvent(){
118    if(!buffer.isEmpty())
119      return buffer.pop();
120    else
121      return NULL;
122  }
123
124  bool ConnectionManager::queueEmpty() {
125    return buffer.isEmpty();
126  }
127
128  void ConnectionManager::createListener() {
129    receiverThread_ = new boost::thread(boost::bind(&ConnectionManager::receiverThread, this));
130    return;
131  }
132
133  bool ConnectionManager::quitListener() {
134    quit=true;
135    receiverThread_->join();
136    return true;
137  }
138
139
140  bool ConnectionManager::addPacket(ENetPacket *packet, ENetPeer *peer) {
141    boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
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(enet_mutex_g);
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_g);
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_g);
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_g);
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        case ENET_EVENT_TYPE_DISCONNECT:
210        case ENET_EVENT_TYPE_RECEIVE:
211            processData(event);
212            event = new ENetEvent;
213          break;
214        case ENET_EVENT_TYPE_NONE:
215          //receiverThread_->yield();
216          msleep(1);
217          break;
218      }
219//       usleep(100);
220      //receiverThread_->yield(); //TODO: find apropriate
221    }
222    disconnectClients();
223    // if we're finishied, destroy server
224    {
225      boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
226      enet_host_destroy(server);
227      lock.unlock();
228    }
229  }
230
231  //### added some bugfixes here, but we cannot test them because
232  //### the server crashes everytime because of some gamestates
233  //### (trying to resolve that now)
234  void ConnectionManager::disconnectClients() {
235    ENetEvent event;
236    ClientInformation *temp = ClientInformation::getBegin()->next();
237    while(temp!=0){
238      {
239        boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
240        enet_peer_disconnect(temp->getPeer(), 0);
241        lock.unlock();
242      }
243      temp = temp->next();
244    }
245    //bugfix: might be the reason why server crashes when clients disconnects
246    temp = ClientInformation::getBegin()->next();
247    boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
248    while( temp!=0 && enet_host_service(server, &event, NETWORK_WAIT_TIMEOUT) >= 0){
249      switch (event.type)
250      {
251      case ENET_EVENT_TYPE_NONE: break;
252      case ENET_EVENT_TYPE_CONNECT: break;
253      case ENET_EVENT_TYPE_RECEIVE:
254        enet_packet_destroy(event.packet);
255        break;
256      case ENET_EVENT_TYPE_DISCONNECT:
257        COUT(4) << "disconnecting all clients" << std::endl;
258        if(ClientInformation::findClient(&(event.peer->address)))
259          delete ClientInformation::findClient(&(event.peer->address));
260        //maybe needs bugfix: might also be a reason for the server to crash
261        temp = temp->next();
262        break;
263      }
264    }
265    return;
266  }
267
268  bool ConnectionManager::processData(ENetEvent *event) {
269    // just add packet to the buffer
270    // this can be extended with some preprocessing
271    return buffer.push(event);
272  }
273
274
275
276  int ConnectionManager::getClientID(ENetPeer* peer) {
277    return getClientID(&(peer->address));
278  }
279
280  int ConnectionManager::getClientID(ENetAddress* address) {
281    return ClientInformation::findClient(address)->getID();
282  }
283
284  ENetPeer *ConnectionManager::getClientPeer(int clientID) {
285    return ClientInformation::findClient(clientID)->getPeer();
286  }
287
288
289  void ConnectionManager::syncClassid(unsigned int clientID) {
290    int failures=0;
291    packet::ClassID *classid = new packet::ClassID();
292    classid->setClientID(clientID);
293    while(!classid->send() && failures < 10){
294      failures++;
295    }
296    assert(failures<10);
297    COUT(4) << "syncClassid:\tall synchClassID packets have been sent" << std::endl;
298  }
299 
300
301  void ConnectionManager::disconnectClient(ClientInformation *client){
302    {
303      boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
304      enet_peer_disconnect(client->getPeer(), 0);
305      lock.unlock();
306    }
307  }
308
309
310}
Note: See TracBrowser for help on using the repository browser.