2011-12-14 00:23:17 +03:00
# include "StdInc.h"
2013-01-12 13:32:03 +03:00
# include <boost/asio.hpp>
2013-07-28 17:49:50 +03:00
# include "../lib/filesystem/Filesystem.h"
2013-04-07 13:48:07 +03:00
# include "../lib/mapping/CCampaignHandler.h"
2011-12-14 00:23:17 +03:00
# include "../lib/CThreadHelper.h"
2008-07-03 18:03:32 +03:00
# include "../lib/Connection.h"
2012-08-10 16:07:53 +03:00
# include "../lib/CModHandler.h"
2010-12-20 23:22:53 +02:00
# include "../lib/CArtHandler.h"
# include "../lib/CDefObjInfoHandler.h"
# include "../lib/CGeneralTextHandler.h"
# include "../lib/CHeroHandler.h"
# include "../lib/CTownHandler.h"
# include "../lib/CBuildingHandler.h"
# include "../lib/CSpellHandler.h"
# include "../lib/CCreatureHandler.h"
2008-07-09 20:22:28 +03:00
# include "zlib.h"
2008-07-25 20:28:28 +03:00
# include "CVCMIServer.h"
2011-12-14 00:23:17 +03:00
# include "../lib/StartInfo.h"
2013-04-07 13:48:07 +03:00
# include "../lib/mapping/CMap.h"
2008-09-12 11:51:46 +03:00
# include "../lib/Interprocess.h"
2008-07-25 20:28:28 +03:00
# include "../lib/VCMI_Lib.h"
2009-10-10 08:47:59 +03:00
# include "../lib/VCMIDirs.h"
2008-07-25 20:28:28 +03:00
# include "CGameHandler.h"
2013-04-07 13:48:07 +03:00
# include "../lib/mapping/CMapInfo.h"
2011-12-14 00:23:17 +03:00
# include "../lib/CObjectHandler.h"
# include "../lib/GameConstants.h"
2013-04-10 20:18:01 +03:00
# include "../lib/logging/CBasicLogConfigurator.h"
# include "../lib/CConfigHandler.h"
2013-04-21 19:38:31 +03:00
# include "../lib/ScopeGuard.h"
2011-12-14 00:23:17 +03:00
2012-02-20 00:03:43 +03:00
# include "../lib/UnlockGuard.h"
2010-10-24 14:35:14 +03:00
2014-01-05 20:48:50 +03:00
# if defined(__GNUC__) && !defined (__MINGW32__)
2013-12-28 15:47:55 +03:00
# include <execinfo.h>
# endif
2009-07-31 23:10:22 +03:00
std : : string NAME_AFFIX = " server " ;
2011-12-14 00:23:17 +03:00
std : : string NAME = GameConstants : : VCMI_VERSION + std : : string ( " ( " ) + NAME_AFFIX + ' ) ' ; //application name
2008-07-02 11:39:56 +03:00
using namespace boost ;
using namespace boost : : asio ;
2008-07-03 18:03:32 +03:00
using namespace boost : : asio : : ip ;
2008-09-12 11:51:46 +03:00
namespace intpr = boost : : interprocess ;
2008-08-04 12:05:52 +03:00
bool end2 = false ;
2008-09-09 04:40:43 +03:00
int port = 3030 ;
2008-07-25 20:28:28 +03:00
2013-06-21 23:59:32 +03:00
boost : : program_options : : variables_map cmdLineOptions ;
2009-04-15 17:03:31 +03:00
/*
* CVCMIServer . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2009-05-24 01:57:39 +03:00
static void vaccept ( tcp : : acceptor * ac , tcp : : socket * s , boost : : system : : error_code * error )
2008-09-12 11:51:46 +03:00
{
ac - > accept ( * s , * error ) ;
}
2010-10-24 14:35:14 +03:00
2013-06-26 14:18:27 +03:00
CPregameServer : : CPregameServer ( CConnection * Host , TAcceptor * Acceptor /*= nullptr*/ )
: host ( Host ) , listeningThreads ( 0 ) , acceptor ( Acceptor ) , upcomingConnection ( nullptr ) ,
curmap ( nullptr ) , curStartInfo ( nullptr ) , state ( RUNNING )
2010-10-24 14:35:14 +03:00
{
initConnection ( host ) ;
}
void CPregameServer : : handleConnection ( CConnection * cpc )
{
2013-02-14 18:19:35 +03:00
setThreadName ( " CPregameServer::handleConnection " ) ;
2010-10-24 14:35:14 +03:00
try
{
while ( ! cpc - > receivedStop )
{
2013-06-26 14:18:27 +03:00
CPackForSelectionScreen * cpfs = nullptr ;
2010-10-24 14:35:14 +03:00
* cpc > > cpfs ;
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " Got package to announce " < < typeid ( * cpfs ) . name ( ) < < " from " < < * cpc ;
2010-10-24 14:35:14 +03:00
boost : : unique_lock < boost : : recursive_mutex > queueLock ( mx ) ;
bool quitting = dynamic_cast < QuitMenuWithoutStarting * > ( cpfs ) ,
startingGame = dynamic_cast < StartWithCurrentSettings * > ( cpfs ) ;
if ( quitting | | startingGame ) //host leaves main menu or wants to start game -> we end
{
cpc - > receivedStop = true ;
if ( ! cpc - > sendStop )
sendPack ( cpc , * cpfs ) ;
if ( cpc = = host )
toAnnounce . push_back ( cpfs ) ;
}
else
toAnnounce . push_back ( cpfs ) ;
if ( startingGame )
{
//wait for sending thread to announce start
2012-02-20 00:03:43 +03:00
auto unlock = vstd : : makeUnlockGuard ( mx ) ;
2010-10-24 14:35:14 +03:00
while ( state = = RUNNING ) boost : : this_thread : : sleep ( boost : : posix_time : : milliseconds ( 50 ) ) ;
}
}
}
catch ( const std : : exception & e )
{
boost : : unique_lock < boost : : recursive_mutex > queueLock ( mx ) ;
2013-04-10 20:18:01 +03:00
logNetwork - > errorStream ( ) < < * cpc < < " dies... \n What happened: " < < e . what ( ) ;
2010-10-24 14:35:14 +03:00
}
boost : : unique_lock < boost : : recursive_mutex > queueLock ( mx ) ;
if ( state ! = ENDING_AND_STARTING_GAME )
{
connections - = cpc ;
//notify other players about leaving
2013-06-29 16:05:48 +03:00
auto pl = new PlayerLeft ( ) ;
2010-10-24 14:35:14 +03:00
pl - > playerID = cpc - > connectionID ;
announceTxt ( cpc - > name + " left the game " ) ;
toAnnounce . push_back ( pl ) ;
2013-11-03 15:51:25 +03:00
if ( connections . empty ( ) )
2010-10-24 14:35:14 +03:00
{
2013-04-10 20:18:01 +03:00
logNetwork - > errorStream ( ) < < " Last connection lost, server will close itself... " ;
2010-10-24 14:35:14 +03:00
boost : : this_thread : : sleep ( boost : : posix_time : : seconds ( 2 ) ) ; //we should never be hasty when networking
state = ENDING_WITHOUT_START ;
}
}
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " Thread listening for " < < * cpc < < " ended " ;
2010-10-24 14:35:14 +03:00
listeningThreads - - ;
2011-12-14 00:23:17 +03:00
vstd : : clear_pointer ( cpc - > handler ) ;
2010-10-24 14:35:14 +03:00
}
void CPregameServer : : run ( )
{
startListeningThread ( host ) ;
start_async_accept ( ) ;
while ( state = = RUNNING )
{
{
boost : : unique_lock < boost : : recursive_mutex > myLock ( mx ) ;
2013-11-03 15:51:25 +03:00
while ( ! toAnnounce . empty ( ) )
2010-10-24 14:35:14 +03:00
{
processPack ( toAnnounce . front ( ) ) ;
toAnnounce . pop_front ( ) ;
}
// //we end sending thread if we ordered all our connections to stop
// ending = true;
2013-06-29 16:05:48 +03:00
// for(CPregameConnection *pc : connections)
2010-10-24 14:35:14 +03:00
// if(!pc->sendStop)
// ending = false;
if ( state ! = RUNNING )
{
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " Stopping listening for connections... " ;
2010-10-24 14:35:14 +03:00
acceptor - > close ( ) ;
}
if ( acceptor )
{
2011-08-05 02:49:32 +03:00
acceptor - > get_io_service ( ) . reset ( ) ;
acceptor - > get_io_service ( ) . poll ( ) ;
2010-10-24 14:35:14 +03:00
}
} //frees lock
boost : : this_thread : : sleep ( boost : : posix_time : : milliseconds ( 50 ) ) ;
}
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " Thread handling connections ended " ;
2010-10-24 14:35:14 +03:00
if ( state = = ENDING_AND_STARTING_GAME )
{
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " Waiting for listening thread to finish... " ;
2010-10-24 14:35:14 +03:00
while ( listeningThreads ) boost : : this_thread : : sleep ( boost : : posix_time : : milliseconds ( 50 ) ) ;
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " Preparing new game " ;
2010-10-24 14:35:14 +03:00
}
}
CPregameServer : : ~ CPregameServer ( )
{
delete acceptor ;
delete upcomingConnection ;
2013-06-29 16:05:48 +03:00
for ( CPackForSelectionScreen * pack : toAnnounce )
2010-10-24 14:35:14 +03:00
delete pack ;
toAnnounce . clear ( ) ;
//TODO pregameconnections
}
void CPregameServer : : connectionAccepted ( const boost : : system : : error_code & ec )
{
if ( ec )
{
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " Something wrong during accepting: " < < ec . message ( ) ;
2010-10-24 14:35:14 +03:00
return ;
}
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " We got a new connection! :) " ;
2010-10-24 14:35:14 +03:00
CConnection * pc = new CConnection ( upcomingConnection , NAME ) ;
initConnection ( pc ) ;
2013-06-26 14:18:27 +03:00
upcomingConnection = nullptr ;
2010-10-24 14:35:14 +03:00
startListeningThread ( pc ) ;
2013-07-02 19:48:01 +03:00
* pc < < ( ui8 ) pc - > connectionID < < curmap ;
2010-10-24 14:35:14 +03:00
announceTxt ( pc - > name + " joins the game " ) ;
2013-06-29 16:05:48 +03:00
auto pj = new PlayerJoined ( ) ;
2010-10-24 14:35:14 +03:00
pj - > playerName = pc - > name ;
pj - > connectionID = pc - > connectionID ;
toAnnounce . push_back ( pj ) ;
start_async_accept ( ) ;
}
void CPregameServer : : start_async_accept ( )
{
assert ( ! upcomingConnection ) ;
assert ( acceptor ) ;
2011-08-05 02:49:32 +03:00
upcomingConnection = new TSocket ( acceptor - > get_io_service ( ) ) ;
2013-07-02 18:23:32 +03:00
acceptor - > async_accept ( * upcomingConnection , boost : : bind ( & CPregameServer : : connectionAccepted , this , _1 ) ) ;
2010-10-24 14:35:14 +03:00
}
void CPregameServer : : announceTxt ( const std : : string & txt , const std : : string & playerName /*= "system"*/ )
{
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < playerName < < " says: " < < txt ;
2010-10-24 14:35:14 +03:00
ChatMessage cm ;
cm . playerName = playerName ;
cm . message = txt ;
boost : : unique_lock < boost : : recursive_mutex > queueLock ( mx ) ;
toAnnounce . push_front ( new ChatMessage ( cm ) ) ;
}
void CPregameServer : : announcePack ( const CPackForSelectionScreen & pack )
{
2013-06-29 16:05:48 +03:00
for ( CConnection * pc : connections )
2010-10-24 14:35:14 +03:00
sendPack ( pc , pack ) ;
}
void CPregameServer : : sendPack ( CConnection * pc , const CPackForSelectionScreen & pack )
{
if ( ! pc - > sendStop )
{
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " \t Sending pack of type " < < typeid ( pack ) . name ( ) < < " to " < < * pc ;
2010-10-24 14:35:14 +03:00
* pc < < & pack ;
}
if ( dynamic_cast < const QuitMenuWithoutStarting * > ( & pack ) )
{
pc - > sendStop = true ;
}
else if ( dynamic_cast < const StartWithCurrentSettings * > ( & pack ) )
{
pc - > sendStop = true ;
}
}
void CPregameServer : : processPack ( CPackForSelectionScreen * pack )
{
if ( dynamic_cast < CPregamePackToHost * > ( pack ) )
{
sendPack ( host , * pack ) ;
}
else if ( SelectMap * sm = dynamic_cast < SelectMap * > ( pack ) )
{
2011-12-14 00:23:17 +03:00
vstd : : clear_pointer ( curmap ) ;
2010-10-24 14:35:14 +03:00
curmap = sm - > mapInfo ;
sm - > free = false ;
announcePack ( * pack ) ;
}
else if ( UpdateStartOptions * uso = dynamic_cast < UpdateStartOptions * > ( pack ) )
{
2011-12-14 00:23:17 +03:00
vstd : : clear_pointer ( curStartInfo ) ;
2010-10-24 14:35:14 +03:00
curStartInfo = uso - > options ;
uso - > free = false ;
announcePack ( * pack ) ;
}
else if ( dynamic_cast < const StartWithCurrentSettings * > ( pack ) )
{
state = ENDING_AND_STARTING_GAME ;
announcePack ( * pack ) ;
}
else
announcePack ( * pack ) ;
delete pack ;
}
void CPregameServer : : initConnection ( CConnection * c )
{
* c > > c - > name ;
connections . insert ( c ) ;
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " Pregame connection with player " < < c - > name < < " established! " ;
2010-10-24 14:35:14 +03:00
}
void CPregameServer : : startListeningThread ( CConnection * pc )
{
listeningThreads + + ;
2013-02-14 18:19:35 +03:00
pc - > enterPregameConnectionMode ( ) ;
2010-10-24 14:35:14 +03:00
pc - > handler = new boost : : thread ( & CPregameServer : : handleConnection , this , pc ) ;
}
2008-07-25 20:28:28 +03:00
CVCMIServer : : CVCMIServer ( )
2013-06-26 14:18:27 +03:00
: io ( new boost : : asio : : io_service ( ) ) , acceptor ( new TAcceptor ( * io , tcp : : endpoint ( tcp : : v4 ( ) , port ) ) ) , firstConnection ( nullptr )
2008-07-02 11:39:56 +03:00
{
2013-04-10 20:18:01 +03:00
logNetwork - > debugStream ( ) < < " CVCMIServer created! " ;
2008-07-25 20:28:28 +03:00
}
CVCMIServer : : ~ CVCMIServer ( )
{
2008-07-27 20:07:37 +03:00
//delete io;
//delete acceptor;
2013-04-21 20:06:24 +03:00
//delete firstConnection;
2008-07-25 20:28:28 +03:00
}
2010-10-24 14:35:14 +03:00
CGameHandler * CVCMIServer : : initGhFromHostingConnection ( CConnection & c )
2008-07-25 20:28:28 +03:00
{
2013-06-29 16:05:48 +03:00
auto gh = new CGameHandler ( ) ;
2010-10-24 14:35:14 +03:00
StartInfo si ;
c > > si ; //get start options
2010-05-08 21:56:38 +03:00
2013-05-21 22:08:06 +03:00
if ( ! si . createRandomMap ( ) )
2008-07-09 20:22:28 +03:00
{
2012-11-20 20:53:45 +03:00
bool mapFound = CResourceHandler : : get ( ) - > existsResource ( ResourceID ( si . mapname , EResType : : MAP ) ) ;
//TODO some checking for campaigns
if ( ! mapFound & & si . mode = = StartInfo : : NEW_GAME )
{
c < < ui8 ( 1 ) ; //WRONG!
return nullptr ;
}
2008-07-02 11:39:56 +03:00
}
2008-07-25 20:28:28 +03:00
2012-11-20 20:53:45 +03:00
c < < ui8 ( 0 ) ; //OK!
2012-03-27 23:08:54 +03:00
gh - > init ( & si ) ;
2010-10-24 14:35:14 +03:00
gh - > conns . insert ( & c ) ;
2008-07-25 20:28:28 +03:00
2010-10-24 14:35:14 +03:00
return gh ;
}
void CVCMIServer : : newGame ( )
{
CConnection & c = * firstConnection ;
ui8 clients ;
c > > clients ; //how many clients should be connected
assert ( clients = = 1 ) ; //multi goes now by newPregame, TODO: custom lobbies
CGameHandler * gh = initGhFromHostingConnection ( c ) ;
2013-04-21 19:38:31 +03:00
auto onExit = vstd : : makeScopeGuard ( [ & ] ( )
{
vstd : : clear_pointer ( gh ) ;
} ) ;
2010-10-24 14:35:14 +03:00
gh - > run ( false ) ;
}
void CVCMIServer : : newPregame ( )
{
2013-06-29 16:05:48 +03:00
auto cps = new CPregameServer ( firstConnection , acceptor ) ;
2010-10-24 14:35:14 +03:00
cps - > run ( ) ;
if ( cps - > state = = CPregameServer : : ENDING_WITHOUT_START )
2008-07-02 11:39:56 +03:00
{
2010-10-24 14:35:14 +03:00
delete cps ;
return ;
2008-07-03 18:03:32 +03:00
}
2008-07-25 20:28:28 +03:00
2010-10-24 14:35:14 +03:00
if ( cps - > state = = CPregameServer : : ENDING_AND_STARTING_GAME )
{
CGameHandler gh ;
gh . conns = cps - > connections ;
2012-03-27 23:08:54 +03:00
gh . init ( cps - > curStartInfo ) ;
2010-10-24 14:35:14 +03:00
2013-06-29 16:05:48 +03:00
for ( CConnection * c : gh . conns )
2010-10-24 14:35:14 +03:00
c - > addStdVecItems ( gh . gs ) ;
gh . run ( false ) ;
}
2008-07-25 20:28:28 +03:00
}
2010-10-24 14:35:14 +03:00
2008-07-25 20:28:28 +03:00
void CVCMIServer : : start ( )
{
2013-06-26 14:18:27 +03:00
ServerReady * sr = nullptr ;
2008-09-12 11:51:46 +03:00
intpr : : mapped_region * mr ;
try
{
intpr : : shared_memory_object smo ( intpr : : open_only , " vcmi_memory " , intpr : : read_write ) ;
2009-01-31 00:23:13 +02:00
smo . truncate ( sizeof ( ServerReady ) ) ;
2008-09-12 11:51:46 +03:00
mr = new intpr : : mapped_region ( smo , intpr : : read_write ) ;
2009-05-01 17:37:25 +03:00
sr = reinterpret_cast < ServerReady * > ( mr - > get_address ( ) ) ;
2008-09-12 11:51:46 +03:00
}
catch ( . . . )
{
intpr : : shared_memory_object smo ( intpr : : create_only , " vcmi_memory " , intpr : : read_write ) ;
smo . truncate ( sizeof ( ServerReady ) ) ;
mr = new intpr : : mapped_region ( smo , intpr : : read_write ) ;
sr = new ( mr - > get_address ( ) ) ServerReady ( ) ;
}
2008-07-25 20:28:28 +03:00
boost : : system : : error_code error ;
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " Listening for connections at port " < < acceptor - > local_endpoint ( ) . port ( ) ;
2013-06-29 16:05:48 +03:00
auto s = new tcp : : socket ( acceptor - > get_io_service ( ) ) ;
2013-07-02 18:23:32 +03:00
boost : : thread acc ( boost : : bind ( vaccept , acceptor , s , & error ) ) ;
2008-09-12 11:51:46 +03:00
sr - > setToTrueAndNotify ( ) ;
delete mr ;
2010-10-24 14:35:14 +03:00
2008-09-12 11:51:46 +03:00
acc . join ( ) ;
2008-07-25 20:28:28 +03:00
if ( error )
2008-07-03 18:03:32 +03:00
{
2013-04-10 20:18:01 +03:00
logNetwork - > warnStream ( ) < < " Got connection but there is an error " < < error ;
2008-07-25 20:28:28 +03:00
return ;
}
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " We've accepted someone... " ;
2010-10-24 14:35:14 +03:00
firstConnection = new CConnection ( s , NAME ) ;
2013-04-10 20:18:01 +03:00
logNetwork - > infoStream ( ) < < " Got connection! " ;
2008-08-04 12:05:52 +03:00
while ( ! end2 )
2008-07-25 20:28:28 +03:00
{
2009-10-14 15:44:44 +03:00
ui8 mode ;
2010-10-24 14:35:14 +03:00
* firstConnection > > mode ;
2008-07-25 20:28:28 +03:00
switch ( mode )
2008-07-09 20:22:28 +03:00
{
2008-07-25 20:28:28 +03:00
case 0 :
2010-10-24 14:35:14 +03:00
firstConnection - > close ( ) ;
2008-07-25 20:28:28 +03:00
exit ( 0 ) ;
case 1 :
2010-10-24 14:35:14 +03:00
firstConnection - > close ( ) ;
2008-07-09 20:22:28 +03:00
return ;
2008-07-25 20:28:28 +03:00
case 2 :
2010-10-24 14:35:14 +03:00
newGame ( ) ;
2008-07-25 20:28:28 +03:00
break ;
2009-01-11 00:08:18 +02:00
case 3 :
2010-10-24 14:35:14 +03:00
loadGame ( ) ;
break ;
case 4 :
newPregame ( ) ;
2009-01-11 00:08:18 +02:00
break ;
2008-07-09 20:22:28 +03:00
}
2008-07-02 11:39:56 +03:00
}
2008-07-25 20:28:28 +03:00
}
2008-07-02 11:39:56 +03:00
2010-10-24 14:35:14 +03:00
void CVCMIServer : : loadGame ( )
2009-01-11 00:08:18 +02:00
{
2010-10-24 14:35:14 +03:00
CConnection & c = * firstConnection ;
2009-01-11 00:08:18 +02:00
std : : string fname ;
CGameHandler gh ;
boost : : system : : error_code error ;
ui8 clients ;
2010-10-24 14:35:14 +03:00
c > > clients > > fname ; //how many clients should be connected - TODO: support more than one
2009-01-11 00:08:18 +02:00
2013-02-19 01:37:22 +03:00
// {
// char sig[8];
// CMapHeader dum;
// StartInfo *si;
//
2014-03-08 19:05:23 +03:00
// CLoadFile lf(CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::LIB_SAVEGAME)));
2013-02-19 01:37:22 +03:00
// lf >> sig >> dum >> si;
2013-04-10 20:18:01 +03:00
// logNetwork->infoStream() <<"Reading save signature";
2013-02-19 01:37:22 +03:00
//
// lf >> *VLC;
2013-04-10 20:18:01 +03:00
// logNetwork->infoStream() <<"Reading handlers";
2013-02-19 01:37:22 +03:00
//
// lf >> (gh.gs);
// c.addStdVecItems(gh.gs);
2013-04-10 20:18:01 +03:00
// logNetwork->infoStream() <<"Reading gamestate";
2013-02-19 01:37:22 +03:00
// }
2009-01-11 00:08:18 +02:00
{
2014-03-08 19:05:23 +03:00
CLoadFile lf ( * CResourceHandler : : get ( " local " ) - > getResourceName ( ResourceID ( fname , EResType : : SERVER_SAVEGAME ) ) , minSupportedVersion ) ;
2013-02-19 01:37:22 +03:00
gh . loadCommonState ( lf ) ;
2009-01-11 00:08:18 +02:00
lf > > gh ;
}
2010-10-24 14:35:14 +03:00
c < < ui8 ( 0 ) ;
2009-01-11 00:08:18 +02:00
CConnection * cc ; //tcp::socket * ss;
for ( int i = 0 ; i < clients ; i + + )
{
if ( ! i )
{
2010-10-24 14:35:14 +03:00
cc = & c ;
2009-01-11 00:08:18 +02:00
}
else
{
2013-06-29 16:05:48 +03:00
auto s = new tcp : : socket ( acceptor - > get_io_service ( ) ) ;
2009-01-11 00:08:18 +02:00
acceptor - > accept ( * s , error ) ;
if ( error ) //retry
{
2013-04-10 20:18:01 +03:00
logNetwork - > warnStream ( ) < < " Cannot establish connection - retrying... " ;
2009-01-11 00:08:18 +02:00
i - - ;
continue ;
}
cc = new CConnection ( s , NAME ) ;
2010-06-26 19:02:10 +03:00
cc - > addStdVecItems ( gh . gs ) ;
2009-01-11 00:08:18 +02:00
}
gh . conns . insert ( cc ) ;
}
gh . run ( true ) ;
}
2013-06-21 23:59:32 +03:00
static void handleCommandOptions ( int argc , char * argv [ ] )
{
namespace po = boost : : program_options ;
po : : options_description opts ( " Allowed options " ) ;
opts . add_options ( )
( " help,h " , " display help and exit " )
( " version,v " , " display version information and exit " )
( " port " , po : : value < int > ( ) - > default_value ( 3030 ) , " port at which server will listen to connections from client " )
( " resultsFile " , po : : value < std : : string > ( ) - > default_value ( " ./results.txt " ) , " file to which the battle result will be appended. Used only in the DUEL mode. " ) ;
if ( argc > 1 )
{
try
{
po : : store ( po : : parse_command_line ( argc , argv , opts ) , cmdLineOptions ) ;
}
catch ( std : : exception & e )
{
std : : cerr < < " Failure during parsing command-line options: \n " < < e . what ( ) < < std : : endl ;
}
}
po : : notify ( cmdLineOptions ) ;
2014-03-20 21:17:40 +03:00
if ( cmdLineOptions . count ( " help " ) )
{
printf ( " %s - A Heroes of Might and Magic 3 clone \n " , GameConstants : : VCMI_VERSION . c_str ( ) ) ;
printf ( " Copyright (C) 2007-2014 VCMI dev team - see AUTHORS file \n " ) ;
printf ( " This is free software; see the source for copying conditions. There is NO \n " ) ;
printf ( " warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. \n " ) ;
printf ( " \n " ) ;
printf ( " Usage: \n " ) ;
std : : cout < < opts ;
exit ( 0 ) ;
}
if ( cmdLineOptions . count ( " version " ) )
{
printf ( " %s \n " , GameConstants : : VCMI_VERSION . c_str ( ) ) ;
std : : cout < < VCMIDirs : : get ( ) . genHelpString ( ) ;
exit ( 0 ) ;
}
2013-06-21 23:59:32 +03:00
}
2014-01-05 20:48:50 +03:00
# if defined(__GNUC__) && !defined (__MINGW32__)
2013-12-28 15:47:55 +03:00
void handleLinuxSignal ( int sig )
{
const int STACKTRACE_SIZE = 100 ;
void * buffer [ STACKTRACE_SIZE ] ;
int ptrCount = backtrace ( buffer , STACKTRACE_SIZE ) ;
char * * strings ;
logGlobal - > errorStream ( ) < < " Error: signal " < < sig < < " : " ;
strings = backtrace_symbols ( buffer , ptrCount ) ;
if ( strings = = nullptr )
{
logGlobal - > errorStream ( ) < < " There are no symbols. " ;
}
else
{
for ( int i = 0 ; i < ptrCount ; + + i )
{
logGlobal - > errorStream ( ) < < strings [ i ] ;
}
free ( strings ) ;
}
_exit ( EXIT_FAILURE ) ;
}
# endif
2008-09-10 00:10:24 +03:00
int main ( int argc , char * * argv )
2008-07-01 11:01:02 +03:00
{
2013-12-28 15:47:55 +03:00
// Installs a sig sev segmentation violation handler
// to log stacktrace
2014-01-05 20:48:50 +03:00
# if defined(__GNUC__) && !defined (__MINGW32__)
2013-12-28 15:47:55 +03:00
signal ( SIGSEGV , handleLinuxSignal ) ;
# endif
2008-09-17 13:18:22 +03:00
console = new CConsoleHandler ;
2013-07-08 23:55:22 +03:00
CBasicLogConfigurator logConfig ( VCMIDirs : : get ( ) . userCachePath ( ) + " /VCMI_Server_log.txt " , console ) ;
2013-06-21 23:59:32 +03:00
logConfig . configureDefault ( ) ;
2013-04-14 21:52:05 +03:00
2013-04-11 18:58:01 +03:00
preinitDLL ( console ) ;
2013-04-10 20:18:01 +03:00
settings . init ( ) ;
2013-06-21 23:59:32 +03:00
logConfig . configure ( ) ;
handleCommandOptions ( argc , argv ) ;
port = cmdLineOptions [ " port " ] . as < int > ( ) ;
logNetwork - > infoStream ( ) < < " Port " < < port < < " will be used. " ;
2013-04-10 20:18:01 +03:00
2012-12-12 14:13:57 +03:00
loadDLLClasses ( ) ;
2013-06-26 14:18:27 +03:00
srand ( ( ui32 ) time ( nullptr ) ) ;
2008-07-25 20:28:28 +03:00
try
{
io_service io_service ;
CVCMIServer server ;
2012-11-16 00:29:22 +03:00
try
2008-09-12 11:51:46 +03:00
{
2012-11-16 00:29:22 +03:00
while ( ! end2 )
{
server . start ( ) ;
}
io_service . run ( ) ;
2008-09-12 11:51:46 +03:00
}
2012-11-16 00:29:22 +03:00
catch ( boost : : system : : system_error & e ) //for boost errors just log, not crash - probably client shut down connection
{
2013-04-10 20:18:01 +03:00
logNetwork - > errorStream ( ) < < e . what ( ) ;
2012-11-16 00:29:22 +03:00
end2 = true ;
2013-12-28 15:47:55 +03:00
}
catch ( . . . )
{
handleException ( ) ;
}
2012-11-16 00:29:22 +03:00
}
catch ( boost : : system : : system_error & e )
2009-09-20 15:47:40 +03:00
{
2013-04-10 20:18:01 +03:00
logNetwork - > errorStream ( ) < < e . what ( ) ;
2012-11-16 00:29:22 +03:00
//catch any startup errors (e.g. can't access port) errors
//and return non-zero status so client can detect error
throw ;
}
2013-04-21 19:38:31 +03:00
//delete VLC; //can't be re-enabled due to access to already freed memory in bonus system
CResourceHandler : : clear ( ) ;
2012-11-16 00:29:22 +03:00
2008-07-01 11:01:02 +03:00
return 0 ;
2008-07-02 11:39:56 +03:00
}