Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

merged netp4 back to trunk

  • Property svn:eol-style set to native
File size: 9.1 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/Debug.h"
51#include "util/Math.h"
52#include "util/Sleep.h"
53#include "ClientInformation.h"
54#include "synchronisable/Synchronisable.h"
55#include "packet/ClassID.h"
56
57namespace std
58{
59  bool operator< (ENetAddress a, ENetAddress b) {
60    return a.host <= b.host;
61  }
62}
63
64namespace orxonox
65{
66  //boost::thread_group network_threads;
67  static boost::recursive_mutex enet_mutex_g;
68
69  ConnectionManager *ConnectionManager::instance_=0;
70
71  ConnectionManager::ConnectionManager():receiverThread_(0){
72    assert(instance_==0);
73    instance_=this;
74    quit_=false;
75    bindAddress = new ENetAddress();
76    bindAddress->host = ENET_HOST_ANY;
77    bindAddress->port = NETWORK_PORT;
78  }
79
80  ConnectionManager::ConnectionManager(int port){
81    assert(instance_==0);
82    instance_=this;
83    quit_=false;
84    bindAddress = new ENetAddress();
85    bindAddress->host = ENET_HOST_ANY;
86    bindAddress->port = port;
87  }
88
89  ConnectionManager::ConnectionManager(int port, const std::string& address) :receiverThread_(0) {
90    assert(instance_==0);
91    instance_=this;
92    quit_=false;
93    bindAddress = new ENetAddress();
94    enet_address_set_host (bindAddress, address.c_str());
95    bindAddress->port = NETWORK_PORT;
96  }
97
98  ConnectionManager::ConnectionManager(int port, const char *address) : receiverThread_(0) {
99    assert(instance_==0);
100    instance_=this;
101    quit_=false;
102    bindAddress = new ENetAddress();
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    delete bindAddress;
112  }
113
114
115  ENetEvent *ConnectionManager::getEvent(){
116    if(!buffer.isEmpty())
117      return buffer.pop();
118    else
119      return NULL;
120  }
121
122  bool ConnectionManager::queueEmpty() {
123    return buffer.isEmpty();
124  }
125
126  void ConnectionManager::createListener() {
127    receiverThread_ = new boost::thread(boost::bind(&ConnectionManager::receiverThread, this));
128    return;
129  }
130
131  bool ConnectionManager::quitListener() {
132    quit_=true;
133    receiverThread_->join();
134    delete receiverThread_;
135    return true;
136  }
137
138
139  bool ConnectionManager::addPacket(ENetPacket *packet, ENetPeer *peer) {
140    boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
141    if(enet_peer_send(peer, NETWORK_DEFAULT_CHANNEL, packet)!=0)
142      return false;
143    return true;
144  }
145
146  bool ConnectionManager::addPacket(ENetPacket *packet, unsigned int clientID) {
147    if ( clientID == CLIENTID_UNKNOWN )
148    {
149      return addPacketAll(packet);
150    }
151    else
152    {
153      ClientInformation *temp = ClientInformation::findClient(clientID);
154      if(!temp){
155        COUT(3) << "C.Man: addPacket findClient failed" << std::endl;
156        return false;
157      }
158      return addPacket(packet, temp->getPeer());
159    }
160  }
161
162  bool ConnectionManager::addPacketAll(ENetPacket *packet) {
163    if(!instance_)
164      return false;
165    boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
166//    for(ClientInformation *i=ClientInformation::getBegin()->next(); i!=0; i=i->next()){
167//      COUT(3) << "adding broadcast packet for client: " << i->getID() << std::endl;
168//      if(enet_peer_send(i->getPeer(), 0, packet)!=0)
169//        return false;
170//    }
171    enet_host_broadcast( instance_->server, 0, packet);
172    return true;
173  }
174
175  // we actually dont need that function, because host_service does that for us
176  bool ConnectionManager::sendPackets() {
177    if(server==NULL || !instance_)
178      return false;
179    boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
180    enet_host_flush(server);
181    lock.unlock();
182    return true;
183  }
184
185  void ConnectionManager::receiverThread() {
186    // what about some error-handling here ?
187    ENetEvent *event;
188    atexit(enet_deinitialize);
189    { //scope of the mutex
190      boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
191      enet_initialize();
192      server = enet_host_create(bindAddress, NETWORK_MAX_CONNECTIONS, 0, 0);
193      lock.unlock();
194    }
195    if(server==NULL){
196      // add some error handling here ==========================
197      quit_=true;
198      return;
199    }
200
201    event = new ENetEvent;
202    while(!quit_)
203    {
204      { //mutex scope
205        boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
206        if(enet_host_service(server, event, NETWORK_WAIT_TIMEOUT)<0){
207          // we should never reach this point
208          printf("ConnectionManager: ENet returned with an error\n");
209//           quit_=true;
210//           printf("waaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahhhhhhhhhhhhhhhh\n");
211          continue;
212          // add some error handling here ========================
213        }
214        lock.unlock();
215      }
216      switch(event->type){
217        // log handling ================
218        case ENET_EVENT_TYPE_CONNECT:
219//             printf("====================================================================");
220        case ENET_EVENT_TYPE_DISCONNECT:
221//           printf("====================================================================");
222        case ENET_EVENT_TYPE_RECEIVE:
223          processData(event);
224          event = new ENetEvent;
225          break;
226        case ENET_EVENT_TYPE_NONE:
227          //receiverThread_->yield();
228          msleep(1);
229          break;
230      }
231//       usleep(100);
232      //receiverThread_->yield(); //TODO: find apropriate
233    }
234    disconnectClients();
235    // if we're finishied, destroy server
236    {
237      boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
238      enet_host_destroy(server);
239      lock.unlock();
240    }
241  }
242
243  //### added some bugfixes here, but we cannot test them because
244  //### the server crashes everytime because of some gamestates
245  //### (trying to resolve that now)
246  void ConnectionManager::disconnectClients() {
247    ENetEvent event;
248    ClientInformation *temp = ClientInformation::getBegin()->next();
249    while(temp!=0){
250      {
251        boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
252        enet_peer_disconnect(temp->getPeer(), 0);
253        lock.unlock();
254      }
255      temp = temp->next();
256    }
257    //bugfix: might be the reason why server crashes when clients disconnects
258    temp = ClientInformation::getBegin()->next();
259    boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
260    while( temp!=0 && enet_host_service(server, &event, NETWORK_WAIT_TIMEOUT) >= 0){
261      switch (event.type)
262      {
263      case ENET_EVENT_TYPE_NONE: break;
264      case ENET_EVENT_TYPE_CONNECT: break;
265      case ENET_EVENT_TYPE_RECEIVE:
266        enet_packet_destroy(event.packet);
267        break;
268      case ENET_EVENT_TYPE_DISCONNECT:
269        COUT(4) << "disconnecting all clients" << std::endl;
270        if(ClientInformation::findClient(&(event.peer->address)))
271          delete ClientInformation::findClient(&(event.peer->address));
272        //maybe needs bugfix: might also be a reason for the server to crash
273        temp = temp->next();
274        break;
275      }
276    }
277    return;
278  }
279
280
281  int ConnectionManager::getClientID(ENetPeer* peer) {
282    return getClientID(&(peer->address));
283  }
284
285  int ConnectionManager::getClientID(ENetAddress* address) {
286    return ClientInformation::findClient(address)->getID();
287  }
288
289  ENetPeer *ConnectionManager::getClientPeer(int clientID) {
290    return ClientInformation::findClient(clientID)->getPeer();
291  }
292
293
294  void ConnectionManager::syncClassid(unsigned int clientID) {
295    int failures=0;
296    packet::ClassID *classid = new packet::ClassID();
297    classid->setClientID(clientID);
298    while(!classid->send() && failures < 10){
299      failures++;
300    }
301    assert(failures<10);
302    COUT(4) << "syncClassid:\tall synchClassID packets have been sent" << std::endl;
303  }
304 
305
306  void ConnectionManager::disconnectClient(ClientInformation *client){
307    {
308      boost::recursive_mutex::scoped_lock lock(enet_mutex_g);
309      enet_peer_disconnect(client->getPeer(), 0);
310      lock.unlock();
311    }
312  }
313
314
315}
Note: See TracBrowser for help on using the repository browser.