Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/output/src/libraries/network/MasterServer.cc @ 8829

Last change on this file since 8829 was 8807, checked in by landauf, 13 years ago

Replaced COUT with orxout in network library. Tried to set levels and contexts in a more or less useful way, but not really optimized. Used contexts network, packets, and master_server.
Please use endl instead of \n in the future (@smerkli) ;)

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