Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/network/MasterServer.cc @ 10107

Last change on this file since 10107 was 8952, checked in by dafrick, 13 years ago

Removing some unused variables and taking care of some other warnings (NULL as argument to non-pointer and depricated use of COUT).

  • Property svn:eol-style set to native
File size: 12.3 KB
RevLine 
[7569]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 *      Sandro 'smerkli' Merkli
24 *   Co-authors:
25 *      ...
26 *
27 */
28
[7565]29#include "MasterServer.h"
[7590]30#include "util/ScopedSingletonManager.h"
[8937]31#include "core/command/ConsoleCommand.h"
[7590]32#include "core/CoreIncludes.h"
33#include "core/CorePrereqs.h"
[8937]34#include "util/Output.h"
[7565]35
[7590]36namespace orxonox
37{
[8937]38  /*** MACROS ***/
39  /* commands for the terminal interface */
40  SetConsoleCommand( "ms-listservers", &MasterServer::listServers );
41  SetConsoleCommand( "ms-delserver", &MasterServer::delServer );
42  //SetConsoleCommand( "ms-serverinfo", &MasterServer::serverInfo );
43
44  /* forward declaration so the linker doesn't complain */
45  MasterServer *MasterServer::instance = NULL;
46
47
48
49
50  /* command: list servers */
51  void 
52  MasterServer::listServers( void )
53  {
54    /* get an iterator */
55    std::list<ServerListElem>::iterator i;
56
57    /* print list header */
58    orxout(user_info) << "List of connected servers" << std::endl;
59
60    /* loop through list elements */
61    for( i = MasterServer::getInstance()->mainlist.serverlist.begin(); 
62      i != MasterServer::getInstance()->mainlist.serverlist.end(); ++i ) 
63    {
64      orxout(user_info) << "  " << (*i).ServerInfo.getServerIP() << std::endl;
65    }
66
67    /* display end of list */
68    orxout(user_info) << MasterServer::getInstance()->mainlist.serverlist.size() <<
69      " servers connected." << std::endl;
70  }
71
72  void 
73  MasterServer::delServer( std::string todeladdr )
74  {
75    /* tell the user we're now removing the entry from the server list */
76    orxout(user_info) << "MS: Deleting server \"" << todeladdr << "\"..." 
77      << std::endl;
78
79    /* see if we actually have that server on our list */
80    ServerListSearchResult shandle = 
81      MasterServer::getInstance()->mainlist.findServerByAddress(todeladdr);
82
83    if( !shandle.success )
84    { orxout(user_info) << "MS: Server not found, not removing." << std::endl;
85      return;
86    }
87
88    /* force-disconnect the server */ 
[8952]89    enet_peer_disconnect( shandle.result.peer, 0 );
[8937]90
91    /* actually remove the entry from the server list by address */
92    MasterServer::getInstance()->mainlist.delServerByAddress( todeladdr);
93
94    /* tell the user about our success */
95    orxout(user_info) << "MS: Server deletion successful." << std::endl;
96  }
97
98
[7684]99  /* helpers */
100  static void 
101  helper_output_debug( ENetEvent *event, char *addrconv )
102  {
[8858]103    orxout(verbose, context::master_server)
104      << "A packet of length" 
[7684]105      << event->packet->dataLength
106      << " containing "
107      << (const char*)event->packet->data
108      << " was received from "
109      << addrconv
110      << " on channel "
[8858]111      << event->channelID << endl;
[7684]112  }
113
114  void
115  MasterServer::helper_sendlist( ENetEvent *event )
116  {
117    /* get an iterator */
[8937]118    std::list<ServerListElem>::iterator i;
[7684]119
120    /* packet holder */
121    ENetPacket *reply;
122
123    /* loop through list elements */
124    for( i = mainlist.serverlist.begin(); i
125        != mainlist.serverlist.end(); ++i ) 
126    {
127      /* send this particular server */
128      /* build reply string */
[8937]129      char *tosend = (char *)calloc( (*i).ServerInfo.getServerIP().length() 
[7684]130          + MSPROTO_SERVERLIST_ITEM_LEN + 2,1 );
131      if( !tosend ) 
[8858]132      { orxout(internal_warning, context::master_server) << "Masterserver.cc: Memory allocation failed." << endl;
[7684]133        continue;
134      } 
135      sprintf( tosend, "%s %s", MSPROTO_SERVERLIST_ITEM, 
[8937]136          (*i).ServerInfo.getServerIP().c_str() );
[7684]137
138      /* create packet from it */
139      reply = enet_packet_create( tosend,
140          strlen( tosend ) + 1, 
141          ENET_PACKET_FLAG_RELIABLE);
142
143      /* Send the reply to the peer over channel id 0. */
144      enet_peer_send( event->peer, 0, reply );
145
146      /* One could just use enet_host_service() instead. */
147      enet_host_flush( this->server );
148
149      /* free the tosend buffer */
150      free( tosend );
151    } 
152
[7750]153    /* create end-of-list packet */
[7684]154    reply = enet_packet_create( MSPROTO_SERVERLIST_END,
155        MSPROTO_SERVERLIST_END_LEN + 1,
156        ENET_PACKET_FLAG_RELIABLE );
157
[7750]158    /* send end-of-list packet */
[7684]159    enet_peer_send( event->peer, 0, reply );
160
161    /* One could just use enet_host_service() instead. */
162    enet_host_flush( this->server );
163  }
164
[8937]165  /* maybe the two methods below can be merged into one and
166   * made to use ENet's RTT functionality to check for disconnected
167   * servers.
168   */
169  void 
170  MasterServer::helper_cleanupServers( void )
171  {
172    /* get an iterator */
173    std::list<ServerListElem>::iterator i;
174     
175    if( mainlist.serverlist.size() == 0 )
176      return;
[7684]177
[8937]178    /* loop through list elements */
179    for( i = mainlist.serverlist.begin(); i
180        != mainlist.serverlist.end(); ++i ) 
181    { /* see if we have a disconnected peer */
182      if( (*i).peer && 
183         ((*i).peer->state == ENET_PEER_STATE_DISCONNECTED ||
184          (*i).peer->state == ENET_PEER_STATE_ZOMBIE ))
185      { 
186        /* Remove it from the list */
187        orxout(internal_warning) << (char*)(*i).peer->data << " timed out.\n";
188        mainlist.delServerByName( (*i).ServerInfo.getServerName() );
[7684]189
[8937]190        /* stop iterating, we manipulated the list */
191        /* TODO note: this only removes one dead server per loop
192         * iteration. not beautiful, but one iteration is ~100ms,
193         * so not really relevant for the moment.
194         */
195        break;
196      }
197    }
198 
199  }
[7684]200
[8937]201
202
203
[7590]204  /***** EVENTS *****/
205  /* connect event */
206  int 
[7611]207  MasterServer::eventConnect( ENetEvent *event )
[7590]208  { /* check for bad parameters */
209    if( !event )
[8858]210    { orxout(internal_warning, context::master_server) << "MasterServer::eventConnect: No event given." << endl;
[7590]211      return -1;
212    }
[7565]213
[7611]214    /* convert address to string. */
215    char *addrconv = (char *) calloc( 50, 1 );
216    enet_address_get_host_ip( &(event->peer->address), addrconv, 49 );
217
[7590]218    /* output debug info */
[8858]219    orxout(verbose, context::master_server) << "A new client connected from " 
[7611]220      << addrconv
221      << " on port " 
[8858]222      << event->peer->address.port << endl;
[7565]223
[7611]224    /* store string form of address here */
225    event->peer->data = addrconv; 
226
227    /* all fine. */
[7590]228    return 0;
[7565]229  }
230
[7590]231  /* disconnect event */
232  int 
[7611]233  MasterServer::eventDisconnect( ENetEvent *event )
[7590]234  { /* check for bad parameters */
235    if( !event )
[8858]236    { orxout(internal_warning, context::master_server) << "No event given." << endl;
[7590]237      return -1;
238    }
[7565]239
[7651]240    /* output that the disconnect happened */
[8858]241    orxout(verbose, context::master_server) << (char*)event->peer->data << " disconnected." << endl;
[7565]242
[7651]243    /* create string from peer data */
244    std::string name = std::string( (char*)event->peer->data );
245
[7590]246    /* remove the server from the list it belongs to */
[7657]247    this->mainlist.delServerByName( name );
[7565]248
[7590]249    /* Reset the peer's client information. */
[7611]250    if( event->peer->data ) free( event->peer->data );
[7651]251
252    /* done */
[7590]253    return 0;
[7565]254  }
255
[7590]256  /* data event */
257  int 
[7611]258  MasterServer::eventData( ENetEvent *event )
[7651]259  { /* validate packet */
[7611]260    if( !event || !(event->packet) || !(event->peer) )
[8858]261    { orxout(internal_warning, context::master_server) << "No complete event given." << endl;
[7590]262      return -1;
263    }
[7611]264     
265    /* generate address in readable form */
266    char *addrconv = (char *) calloc( 50, 1 );
267    enet_address_get_host_ip( &(event->peer->address), addrconv, 49 );
[7590]268
[7750]269    /* output debug info about the data that has come */
[7684]270    helper_output_debug( event, addrconv );
[7590]271
[7630]272    /* GAME SERVER OR CLIENT CONNECTION? */
[7651]273    if( !strncmp( (char *)event->packet->data, MSPROTO_GAME_SERVER, 
274      MSPROTO_GAME_SERVER_LEN ) )
275    { /* Game server */
[7630]276
[7651]277      if( !strncmp( (char *)event->packet->data
278        + MSPROTO_GAME_SERVER_LEN+1, 
279        MSPROTO_REGISTER_SERVER, MSPROTO_REGISTER_SERVER_LEN ) )
280      { /* register new server */
[8937]281        mainlist.addServer( packet::ServerInformation( event ),
282          event->peer );
[7658]283       
284        /* tell people we did so */
[8858]285        orxout(internal_info, context::master_server) << "Added new server to list: " << 
286          packet::ServerInformation( event ).getServerIP() << endl;
[7651]287      }
[7756]288
[7763]289      else if( !strncmp( (char *)event->packet->data
290        + MSPROTO_GAME_SERVER_LEN+1,
291        MSPROTO_SERVERDC, MSPROTO_SERVERDC_LEN ) )
292      {
293        /* create string from peer data */
294        std::string name = std::string( addrconv );
295
296        /* remove the server from the list it belongs to */
[7765]297        this->mainlist.delServerByAddress( name );
[7763]298
299        /* tell the user */
[8858]300        orxout(internal_info, context::master_server) << "Removed server " << name << " from list." << endl;
[7763]301      }
302
[7756]303      /* TODO add hook for disconnect here */
[7651]304    }
305    else if( !strncmp( (char *)event->packet->data, MSPROTO_CLIENT, 
306      MSPROTO_CLIENT_LEN) )
307    { /* client */
308      if( !strncmp( (char *)event->packet->data + MSPROTO_CLIENT_LEN+1,
[7657]309        MSPROTO_REQ_LIST, MSPROTO_REQ_LIST_LEN ) )
[7684]310        /* send server list */
311        helper_sendlist( event );
[7651]312    }
313    else
314    { /* bad message, don't do anything. */ } 
315
[7611]316    /* delete addrconv */
317    if( addrconv ) free( addrconv );
318
[7590]319    /* Clean up the packet now that we're done using it. */
320    enet_packet_destroy( event->packet );
321    return 0;
322  }
[7565]323
[7611]324
[7590]325  /**** MAIN ROUTINE *****/
326  int 
327  MasterServer::run()
328  {
329    /***** ENTER MAIN LOOP *****/
330    ENetEvent *event = (ENetEvent *)calloc(sizeof(ENetEvent), sizeof(char));
331    if( event == NULL )
[7611]332    { 
[8858]333      orxout(user_error, context::master_server) << "Could not create ENetEvent structure, exiting." << endl;
[7590]334      exit( EXIT_FAILURE );
335    }
[7565]336
[8937]337    /* check for timed out peers and remove those from * the server list */
338    helper_cleanupServers();
339
340
[7743]341    /* create an iterator for the loop */
342    enet_host_service( this->server, event, 100 );
[7611]343
[7743]344    /* check what type of event it is and react accordingly */
345    switch (event->type)
346    { /* new connection */
347      case ENET_EVENT_TYPE_CONNECT: 
348        eventConnect( event ); break;
[7565]349
[7743]350        /* disconnect */
351      case ENET_EVENT_TYPE_DISCONNECT: 
352        eventDisconnect( event ); break;
353
354        /* incoming data */
355      case ENET_EVENT_TYPE_RECEIVE: eventData( event ); break;
356      default: break;
[7590]357    }
[7565]358
[7590]359    /* done */
360    return 0;
361  } 
[7565]362
[7590]363  /* constructor */
364  MasterServer::MasterServer()
365  {
366    /***** INITIALIZE NETWORKING *****/
367    if( enet_initialize () != 0)
[8858]368    { orxout(user_error, context::master_server) << "An error occurred while initializing ENet." << endl;
[7590]369      exit( EXIT_FAILURE );
370    }
[7565]371
[7590]372    /* register deinitialization */
373    atexit( enet_deinitialize );
[7565]374
[7729]375    /* set the quit flag to false */
376    this->quit = false;
377
[7590]378    /* Bind the server to the default localhost and port ORX_MSERVER_PORT */
379    this->address.host = ENET_HOST_ANY;
380    this->address.port = ORX_MSERVER_PORT;
[7589]381
[7590]382    /* create a host with the above settings (the last two 0 mean: accept
383     * any input/output bandwidth */
384    this->server = enet_host_create( &this->address, ORX_MSERVER_MAXCONNS, 
[7801]385        ORX_MSERVER_MAXCHANS, 0, 0 );
386    assert(this->server);
[7590]387
388    /* see if creation worked */
389    if( !this->server )
[8858]390    { orxout(user_error, context::master_server) << 
391        "An error occurred while trying to create an ENet server host." << endl;
[7611]392      exit( EXIT_FAILURE );
[7590]393    }
[7565]394
[8937]395    /* set pointer to this instance */
396    MasterServer::setInstance( this );
[7743]397
398    /* tell people we're now initialized */
[8858]399    orxout(internal_status, context::master_server) << "MasterServer initialized, waiting for connections." << endl;
[7565]400  }
401
[7590]402  /* destructor */
403  MasterServer::~MasterServer()
404  {
405    /***** CLEANUP PROCESS *****/
406    /* terminate all networking connections */
407    enet_host_destroy( this->server );
[7565]408
[7611]409    /* free all used memory */
[7590]410    /* clear the list of connected game servers */
411    /* clear the list of connected game clients */
412  }
413
414/* end of namespace */
415}
Note: See TracBrowser for help on using the repository browser.