Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core3/src/network/ConnectionManager.cc @ 1996

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

Again some heavy changes in ObjectList and Iterator:
there are now two types of iterators:

Iterator<ClassName> can iterate through any objectlist, either given by ObjectList<AnyClassName>::begin() or anyidentifier→getObjects()→begin(). Important note Iterator<ClassName> uses dynamic_cast.
And yes, it's possible to do this: Iterator<WorldEntity> it = ObjectList<SpaceShip>::begin()

ObjectList<ClassName>::iterator is the second iterator - it uses the ObjectList in a templated manner and therefore doesn't need dynamic_cast. But the only thing you can do is iterating through exactly the right ObjectList: ObjectList<ClassName>::iterator it = ObjectList<ClassName>::begin(). Anything else fails.

Those changes bring, at my system, something around +12% FPS compared with trunk and +25% FPS compared with the last revision of core3. Although I have to admit the FPS gain is only that high because iterating through objects is the main thing we're doing ingame right now. It would look totally different with physics, sound, AI, scripts, triggers and so on.

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