Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/masterserver2/src/libraries/network/MasterServer.cc @ 8202

Last change on this file since 8202 was 8202, checked in by smerkli, 15 years ago

done for today

File size: 9.4 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 *      Sandro 'smerkli' Merkli
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "MasterServer.h"
30#include "util/ScopedSingletonManager.h"
31#include "core/CoreIncludes.h"
32#include "core/CorePrereqs.h"
33
34namespace orxonox
35{
36  /* helpers */
37  static void 
38  helper_output_debug( ENetEvent *event, char *addrconv )
39  {
40    COUT(4) << "A packet of length" 
41      << event->packet->dataLength
42      << " containing "
43      << (const char*)event->packet->data
44      << " was received from "
45      << addrconv
46      << " on channel "
47      << event->channelID << "\n";
48  }
49
50  void
51  MasterServer::helper_sendlist( ENetEvent *event )
52  {
53    /* get an iterator */
54    std::list<ServerListElem>::iterator i;
55
56    /* packet holder */
57    ENetPacket *reply;
58
59    /* loop through list elements */
60    for( i = mainlist.serverlist.begin(); i
61        != mainlist.serverlist.end(); ++i ) 
62    {
63      /* send this particular server */
64      /* build reply string */
65      char *tosend = (char *)calloc( (*i).ServerInfo.getServerIP().length() 
66          + MSPROTO_SERVERLIST_ITEM_LEN + 2,1 );
67      if( !tosend ) 
68      { COUT(2) << "Masterserver.cc: Memory allocation failed.\n";
69        continue;
70      } 
71      sprintf( tosend, "%s %s", MSPROTO_SERVERLIST_ITEM, 
72          (*i).ServerInfo.getServerIP().c_str() );
73
74      /* create packet from it */
75      reply = enet_packet_create( tosend,
76          strlen( tosend ) + 1, 
77          ENET_PACKET_FLAG_RELIABLE);
78
79      /* Send the reply to the peer over channel id 0. */
80      enet_peer_send( event->peer, 0, reply );
81
82      /* One could just use enet_host_service() instead. */
83      enet_host_flush( this->server );
84
85      /* free the tosend buffer */
86      free( tosend );
87    } 
88
89    /* create end-of-list packet */
90    reply = enet_packet_create( MSPROTO_SERVERLIST_END,
91        MSPROTO_SERVERLIST_END_LEN + 1,
92        ENET_PACKET_FLAG_RELIABLE );
93
94    /* send end-of-list packet */
95    enet_peer_send( event->peer, 0, reply );
96
97    /* One could just use enet_host_service() instead. */
98    enet_host_flush( this->server );
99  }
100
101  /* maybe the two methods below can be merged into one and
102   * made to use ENet's RTT functionality to check for disconnected
103   * servers.
104   */
105  void 
106  MasterServer::helper_cleanupServers()
107  {
108    /* get an iterator */
109    std::list<ServerListElem>::iterator i;
110
111    /* loop through list elements */
112    for( i = mainlist.serverlist.begin(); i
113        != mainlist.serverlist.end(); ++i ) 
114    {
115      if( mainlist.serverlist.size() != 0 && (*i).peer && 
116         ((*i).peer->state == ENET_PEER_STATE_DISCONNECTED ||
117          (*i).peer->state == ENET_PEER_STATE_ZOMBIE ))
118      { mainlist.delServerByName( (*i).ServerInfo.getServerName() );
119        COUT(2) << "someone timed out.\n";
120      }
121    }
122 
123  }
124
125
126
127
128  /***** EVENTS *****/
129  /* connect event */
130  int 
131  MasterServer::eventConnect( ENetEvent *event )
132  { /* check for bad parameters */
133    if( !event )
134    { COUT(2) << "MasterServer::eventConnect: No event given.\n" ;
135      return -1;
136    }
137
138    /* convert address to string. */
139    char *addrconv = (char *) calloc( 50, 1 );
140    enet_address_get_host_ip( &(event->peer->address), addrconv, 49 );
141
142    /* output debug info */
143    COUT(4) << "A new client connected from " 
144      << addrconv
145      << " on port " 
146      << event->peer->address.port << "\n";
147
148    /* store string form of address here */
149    event->peer->data = addrconv; 
150
151    /* all fine. */
152    return 0;
153  }
154
155  /* disconnect event */
156  int 
157  MasterServer::eventDisconnect( ENetEvent *event )
158  { /* check for bad parameters */
159    if( !event )
160    { COUT(2) << "No event given.\n";
161      return -1;
162    }
163
164    /* output that the disconnect happened */
165    COUT(2) << (char*)event->peer->data << " disconnected.\n";
166
167    /* create string from peer data */
168    std::string name = std::string( (char*)event->peer->data );
169
170    /* remove the server from the list it belongs to */
171    this->mainlist.delServerByName( name );
172
173    /* Reset the peer's client information. */
174    if( event->peer->data ) free( event->peer->data );
175
176    /* done */
177    return 0;
178  }
179
180  /* data event */
181  int 
182  MasterServer::eventData( ENetEvent *event )
183  { /* validate packet */
184    if( !event || !(event->packet) || !(event->peer) )
185    { COUT(2) << "No complete event given.\n";
186      return -1;
187    }
188     
189    /* generate address in readable form */
190    char *addrconv = (char *) calloc( 50, 1 );
191    enet_address_get_host_ip( &(event->peer->address), addrconv, 49 );
192
193    /* output debug info about the data that has come */
194    helper_output_debug( event, addrconv );
195
196    /* GAME SERVER OR CLIENT CONNECTION? */
197    if( !strncmp( (char *)event->packet->data, MSPROTO_GAME_SERVER, 
198      MSPROTO_GAME_SERVER_LEN ) )
199    { /* Game server */
200
201      if( !strncmp( (char *)event->packet->data
202        + MSPROTO_GAME_SERVER_LEN+1, 
203        MSPROTO_REGISTER_SERVER, MSPROTO_REGISTER_SERVER_LEN ) )
204      { /* register new server */
205        mainlist.addServer( packet::ServerInformation( event ),
206          event->peer );
207       
208        /* tell people we did so */
209        COUT(2) << "Added new server to list: " << 
210          packet::ServerInformation( event ).getServerIP() << "\n";
211      }
212
213      else if( !strncmp( (char *)event->packet->data
214        + MSPROTO_GAME_SERVER_LEN+1,
215        MSPROTO_SERVERDC, MSPROTO_SERVERDC_LEN ) )
216      {
217        /* create string from peer data */
218        std::string name = std::string( addrconv );
219
220        /* remove the server from the list it belongs to */
221        this->mainlist.delServerByAddress( name );
222
223        /* tell the user */
224        COUT(2) << "Removed server " << name << " from list.\n";
225      }
226
227      /* TODO add hook for disconnect here */
228    }
229    else if( !strncmp( (char *)event->packet->data, MSPROTO_CLIENT, 
230      MSPROTO_CLIENT_LEN) )
231    { /* client */
232      if( !strncmp( (char *)event->packet->data + MSPROTO_CLIENT_LEN+1,
233        MSPROTO_REQ_LIST, MSPROTO_REQ_LIST_LEN ) )
234        /* send server list */
235        helper_sendlist( event );
236    }
237    else
238    { /* bad message, don't do anything. */ } 
239
240    /* delete addrconv */
241    if( addrconv ) free( addrconv );
242
243    /* Clean up the packet now that we're done using it. */
244    enet_packet_destroy( event->packet );
245    return 0;
246  }
247
248
249  /**** MAIN ROUTINE *****/
250  int 
251  MasterServer::run()
252  {
253    /***** ENTER MAIN LOOP *****/
254    ENetEvent *event = (ENetEvent *)calloc(sizeof(ENetEvent), sizeof(char));
255    if( event == NULL )
256    { 
257      COUT(1) << "Could not create ENetEvent structure, exiting.\n";
258      exit( EXIT_FAILURE );
259    }
260
261    /* check for timed out pings and remove those guys from
262     * the server list
263     */
264    helper_cleanupServers();
265
266
267    /* create an iterator for the loop */
268    enet_host_service( this->server, event, 100 );
269
270    /* check what type of event it is and react accordingly */
271    switch (event->type)
272    { /* new connection */
273      case ENET_EVENT_TYPE_CONNECT: 
274        eventConnect( event ); break;
275
276        /* disconnect */
277      case ENET_EVENT_TYPE_DISCONNECT: 
278        eventDisconnect( event ); break;
279
280        /* incoming data */
281      case ENET_EVENT_TYPE_RECEIVE: eventData( event ); break;
282      default: break;
283    }
284
285    /* done */
286    return 0;
287  } 
288
289  /* constructor */
290  MasterServer::MasterServer()
291  {
292    /***** INITIALIZE NETWORKING *****/
293    if( enet_initialize () != 0)
294    { COUT(1) << "An error occurred while initializing ENet.\n";
295      exit( EXIT_FAILURE );
296    }
297
298    /* register deinitialization */
299    atexit( enet_deinitialize );
300
301    /* set the quit flag to false */
302    this->quit = false;
303
304    /* Bind the server to the default localhost and port ORX_MSERVER_PORT */
305    this->address.host = ENET_HOST_ANY;
306    this->address.port = ORX_MSERVER_PORT;
307
308    /* create a host with the above settings (the last two 0 mean: accept
309     * any input/output bandwidth */
310    this->server = enet_host_create( &this->address, ORX_MSERVER_MAXCONNS, 
311        ORX_MSERVER_MAXCHANS, 0, 0 );
312    assert(this->server);
313
314    /* see if creation worked */
315    if( !this->server )
316    { COUT(1) << 
317        "An error occurred while trying to create an ENet server host.\n";
318      exit( EXIT_FAILURE );
319    }
320
321    /***** INITIALIZE GAME SERVER AND PEER LISTS *****/
322    this->peers = new PeerList();
323
324    /* tell people we're now initialized */
325    COUT(0) << "MasterServer initialized, waiting for connections.\n";
326  }
327
328  /* destructor */
329  MasterServer::~MasterServer()
330  {
331    /***** CLEANUP PROCESS *****/
332    /* terminate all networking connections */
333    enet_host_destroy( this->server );
334
335    /* free all used memory */
336    /* clear the list of connected game servers */
337    /* clear the list of connected game clients */
338  }
339
340/* end of namespace */
341}
Note: See TracBrowser for help on using the repository browser.