Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/network/ConnectionManager.cc @ 1047

Last change on this file since 1047 was 1008, checked in by dumenim, 16 years ago

changed some comments and catched some return values and maybe some stuff we have to unchange

File size: 10.0 KB
Line 
1/*
2*   ORXONOX - the hottest 3D action shooter ever to exist
3*
4*
5*   License notice:
6*
7*   This program is free software; you can redistribute it and/or
8*   modify it under the terms of the GNU General Public License
9*   as published by the Free Software Foundation; either version 2
10*   of the License, or (at your option) any later version.
11*
12*   This program is distributed in the hope that it will be useful,
13*   but WITHOUT ANY WARRANTY; without even the implied warranty of
14*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*   GNU General Public License for more details.
16*
17*   You should have received a copy of the GNU General Public License
18*   along with this program; if not, write to the Free Software
19*   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20*
21*   Author:
22*      Oliver Scheuss, (C) 2007
23*   Co-authors:
24*      ...
25*
26*/
27
28//
29// C++ Interface: ConnectionManager
30//
31// Description: The Class ConnectionManager manages the servers conenctions to the clients.
32// each connection is provided by a new process. communication between master process and
33// connection processes is provided by ...
34//
35//
36// Author:  Oliver Scheuss
37//
38
39#include <iostream>
40// boost.thread library for multithreading support
41#include <boost/thread/thread.hpp>
42#include <boost/bind.hpp>
43
44#include "core/CoreIncludes.h"
45#include "ClientInformation.h"
46#include "ConnectionManager.h"
47
48namespace std
49{
50  bool operator< (ENetAddress a, ENetAddress b) {
51    if(a.host <= b.host)
52      return true;
53    else
54      return false;
55  }
56}
57
58namespace network
59{
60  boost::thread_group network_threads;
61 
62  ConnectionManager::ConnectionManager(){}
63 
64  ConnectionManager::ConnectionManager(ClientInformation *head) {
65    quit=false;
66    bindAddress.host = ENET_HOST_ANY;
67    bindAddress.port = NETWORK_PORT;
68    head_ = head;
69  }
70
71  ConnectionManager::ConnectionManager(int port, std::string address, ClientInformation *head) {
72    quit=false;
73    enet_address_set_host (& bindAddress, address.c_str());
74    bindAddress.port = NETWORK_PORT;
75    head_ = head;
76  }
77
78  ConnectionManager::ConnectionManager(int port, const char *address, ClientInformation *head) {
79    quit=false;
80    enet_address_set_host (& bindAddress, address);
81    bindAddress.port = NETWORK_PORT;
82    head_ = head;
83  }
84
85  ENetPacket *ConnectionManager::getPacket(ENetAddress &address) {
86    if(!buffer.isEmpty())
87      return buffer.pop(address);
88    else
89      return NULL;
90  }
91/**
92This function only pops the first element in PacketBuffer (first in first out)
93used by processQueue in Server.cc
94*/
95  ENetPacket *ConnectionManager::getPacket(int &clientID) {
96    ENetAddress address;
97    ENetPacket *packet=getPacket(address);
98    ClientInformation *temp =head_->findClient(&address);
99    clientID=temp->getID();
100    return packet;
101  }
102
103  bool ConnectionManager::queueEmpty() {
104    return buffer.isEmpty();
105  }
106
107  void ConnectionManager::createListener() {
108    network_threads.create_thread(boost::bind(boost::mem_fn(&ConnectionManager::receiverThread), this));
109    //     boost::thread thr(boost::bind(boost::mem_fn(&ConnectionManager::receiverThread), this));
110    return;
111  }
112
113  bool ConnectionManager::quitListener() {
114    quit=true;
115    network_threads.join_all();
116    return true;
117  }
118
119  bool ConnectionManager::addPacket(ENetPacket *packet, ENetPeer *peer) {
120    if(enet_peer_send(peer, head_->findClient(&(peer->address))->getID() , packet)!=0)
121      return false;
122    return true;
123  }
124
125  bool ConnectionManager::addPacket(ENetPacket *packet, int clientID) {
126    if(enet_peer_send(head_->findClient(clientID)->getPeer(), clientID, packet)!=0)
127      return false;
128    return true;
129  }
130
131  bool ConnectionManager::addPacketAll(ENetPacket *packet) {
132    for(ClientInformation *i=head_->next(); i!=0; i=i->next()){
133      if(enet_peer_send(i->getPeer(), i->getID(), packet)!=0)
134        return false;
135    }
136    return true;
137  }
138
139  bool ConnectionManager::sendPackets(ENetEvent *event) {
140    if(server==NULL)
141      return false;
142    if(enet_host_service(server, event, NETWORK_SEND_WAIT)>=0)
143      return true;
144    else
145      return false;
146  }
147
148  bool ConnectionManager::sendPackets() {
149    ENetEvent event;
150    if(server==NULL)
151      return false;
152    if(enet_host_service(server, &event, NETWORK_SEND_WAIT)>=0)
153      return true;
154    else
155      return false;
156  }
157
158  void ConnectionManager::receiverThread() {
159    // what about some error-handling here ?
160    enet_initialize();
161    atexit(enet_deinitialize);
162    ENetEvent event;
163    server = enet_host_create(&bindAddress, NETWORK_MAX_CONNECTIONS, 0, 0);
164    if(server==NULL){
165      // add some error handling here ==========================
166      quit=true;
167      return;
168    }
169
170    while(!quit){
171      if(enet_host_service(server, &event, NETWORK_WAIT_TIMEOUT)<0){
172        // we should never reach this point
173        quit=true;
174        // add some error handling here ========================
175      }
176      switch(event.type){
177        // log handling ================
178        case ENET_EVENT_TYPE_CONNECT:
179          addClient(&event);
180          COUT(5) << "Con.Man: connection event has occured" << std::endl;
181          break;
182        case ENET_EVENT_TYPE_RECEIVE:
183          //std::cout << "received data" << std::endl;
184          COUT(5) << "Con.Man: receive event has occured" << std::endl;
185          processData(&event);
186          break;
187        case ENET_EVENT_TYPE_DISCONNECT:
188          // add some error/log handling here
189          clientDisconnect(event.peer);
190          break;
191        case ENET_EVENT_TYPE_NONE:
192          break;
193      }
194    }
195    disconnectClients();
196    // if we're finishied, destroy server
197    enet_host_destroy(server);
198  }
199 
200  //### added some bugfixes here, but we cannot test them because
201  //### the server crashes everytime because of some gamestates
202  //### (trying to resolve that now)
203  void ConnectionManager::disconnectClients() {
204    ENetEvent event;
205    ClientInformation *temp = head_->next();
206    while(temp!=0){
207      enet_peer_disconnect(temp->getPeer(), 0);
208      temp = temp->next();
209    }
210    //bugfix: might be the reason why server crashes when clients disconnects
211    //temp = temp->next();
212    temp = head_->next();
213    while( temp!=0 && enet_host_service(server, &event, NETWORK_WAIT_TIMEOUT) > 0){
214      switch (event.type)
215      {
216      case ENET_EVENT_TYPE_NONE: break;
217      case ENET_EVENT_TYPE_CONNECT: break;
218      case ENET_EVENT_TYPE_RECEIVE:
219        enet_packet_destroy(event.packet);
220        break;
221      case ENET_EVENT_TYPE_DISCONNECT:
222        COUT(4) << "disconnecting all clients" << std::endl;
223        delete head_->findClient(&(event.peer->address));
224        //maybe needs bugfix: might also be a reason for the server to crash
225        temp = temp->next();
226        break;
227      }
228    }
229    return;
230  }
231
232  bool ConnectionManager::processData(ENetEvent *event) {
233    // just add packet to the buffer
234    // this can be extended with some preprocessing
235    return buffer.push(event);
236  }
237
238  //bool ConnectionManager::clientDisconnect(ENetPeer *peer) {
239  //  return clientDisconnect(*peer);
240  //}
241
242  bool ConnectionManager::clientDisconnect(ENetPeer *peer) {
243    COUT(4) << "removing client from list" << std::endl;
244    return head_->removeClient(peer);
245  }
246/**
247This function adds a client that connects to the clientlist of the server
248NOTE: if you change this, don't forget to change the test function
249addClientTest in diffTest.cc since addClient is not good for testing because of syncClassid
250*/
251  bool ConnectionManager::addClient(ENetEvent *event) {
252    ClientInformation *temp = head_->insertBack(new ClientInformation);
253    if(temp->prev()->head) { //not good if you use anything else than insertBack
254      temp->prev()->setID(0); //bugfix: not necessary but usefull
255      temp->setID(1);
256    }
257    else
258      temp->setID(temp->prev()->getID()+1);
259    temp->setPeer(event->peer);
260    COUT(4) << "Con.Man: added client id: " << temp->getID() << std::endl;
261    syncClassid(temp->getID());
262    temp->setSynched(true);
263    return true;
264  }
265
266  int ConnectionManager::getClientID(ENetPeer peer) {
267    return getClientID(peer.address);
268  }
269
270  int ConnectionManager::getClientID(ENetAddress address) {
271    return head_->findClient(&address)->getID();
272  }
273
274  ENetPeer *ConnectionManager::getClientPeer(int clientID) {
275    return head_->findClient(clientID)->getPeer();
276  }
277
278  void ConnectionManager::syncClassid(int clientID) {
279    unsigned int network_id=0;
280    std::string classname;
281    orxonox::Identifier *id;
282    std::map<std::string, orxonox::Identifier*>::const_iterator it = orxonox::Factory::getFactoryBegin();
283    while(it != orxonox::Factory::getFactoryEnd()){
284      id = (*it).second;
285      if(id == NULL)
286        continue;
287      classname = id->getName();
288      network_id = id->getNetworkID();
289      COUT(4) << "Con.Man:syncClassid:\tnetwork_id: " << network_id << ", classname: " << classname << std::endl;
290     
291      addPacket(packet_gen.clid( (int)network_id, classname ), clientID);
292     
293      ++it;
294    }
295    sendPackets();
296    COUT(4) << "syncClassid:\tall synchClassID packets have been sent" << std::endl;
297  }
298
299 
300 
301  void ConnectionManager::addClientsObjectID( int clientID, int objectID ) {
302    COUT(4) << "ship of client: " << clientID << ": " << objectID << " mapped" << std::endl;
303    clientsShip.insert( std::make_pair( clientID, objectID ) );
304  }
305
306  int ConnectionManager::getClientsShipID( int clientID ) {
307    return clientsShip[clientID];
308  }
309
310  int ConnectionManager::getObjectsClientID( int objectID ) {
311    std::map<int, int>::iterator iter;
312    for( iter = clientsShip.begin(); iter != clientsShip.end(); iter++ ) {
313      if( iter->second == objectID ) return iter->first;
314    }
315    return -99;
316  }
317
318  void ConnectionManager::deleteClientIDReg( int clientID ) {
319    clientsShip.erase( clientID );
320  }
321
322  void ConnectionManager::deleteObjectIDReg( int objectID ) {
323    std::map<int, int>::iterator iter = clientsShip.begin();
324    for( iter = clientsShip.begin(); iter != clientsShip.end(); iter++ ) {
325      if( iter->second == objectID ) break; 
326    }
327    clientsShip.erase( iter->first );
328  }
329  int ConnectionManager::getNumberOfClients() {
330    return clientsShip.size();
331  }
332}
Note: See TracBrowser for help on using the repository browser.