2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2013 - 2016 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
2012-10-21 20:20:43 +00:00
// network resource: data needed for the game (scenario, plr files, definitions...)
2009-05-08 13:28:41 +00:00
# ifndef INC_C4Network2Res
# define INC_C4Network2Res
2016-04-03 18:07:56 +00:00
# include "lib/StdAdaptors.h"
# include "platform/StdSync.h"
2009-05-08 13:28:41 +00:00
2016-04-03 18:07:56 +00:00
# include "lib/SHA1.h"
2009-05-08 13:28:41 +00:00
2017-03-23 16:03:16 +00:00
# include <atomic>
2009-05-08 13:28:41 +00:00
const uint32_t C4NetResChunkSize = 10U * 1024U ;
const int32_t C4NetResDiscoverTimeout = 10 , // (s)
2011-08-03 23:30:37 +00:00
C4NetResDiscoverInterval = 1 , // (s)
C4NetResStatusInterval = 1 , // (s)
C4NetResMaxLoad = 5 ,
C4NetResLoadTimeout = 60 , // (s)
C4NetResDeleteTime = 60 , // (s)
C4NetResMaxBigicon = 20 ; // maximum size, in KB, of bigicon
2009-05-08 13:28:41 +00:00
const int32_t C4NetResIDAnonymous = - 2 ;
enum C4Network2ResType
{
NRT_Null = 0 ,
NRT_Scenario ,
NRT_Dynamic ,
NRT_Player ,
NRT_Definitions ,
NRT_System ,
2010-01-25 04:00:59 +00:00
NRT_Material
2009-05-08 13:28:41 +00:00
} ;
const StdEnumEntry < C4Network2ResType > C4Network2ResType_EnumMap [ ] =
{
{ " Scenario " , NRT_Scenario } ,
{ " Dynamic " , NRT_Dynamic } ,
{ " Player " , NRT_Player } ,
{ " Definitions " , NRT_Definitions } ,
{ " System " , NRT_System } ,
{ " Material " , NRT_Material } ,
} ;
// damn circular dependencies
2016-04-03 18:07:56 +00:00
# include "network/C4PacketBase.h"
# include "network/C4Network2IO.h"
2009-05-08 13:28:41 +00:00
class C4Network2ResList ;
class C4Network2ResChunk ;
// classes
class C4Network2ResCore : public C4PacketBase
{
public :
C4Network2ResCore ( ) ;
protected :
2017-05-07 11:50:00 +00:00
C4Network2ResType eType { NRT_Null } ;
int32_t iID { - 1 } , iDerID { - 1 } ;
2010-12-05 17:57:06 +00:00
StdCopyStrBuf FileName ;
2017-05-07 11:50:00 +00:00
bool fLoadable { false } ;
2009-05-08 13:28:41 +00:00
uint32_t iFileSize , iFileCRC , iContentsCRC ;
2017-05-07 11:50:00 +00:00
uint8_t fHasFileSHA { false } ;
2009-05-08 13:28:41 +00:00
uint8_t FileSHA [ SHA_DIGEST_LENGTH ] ;
uint32_t iChunkSize ;
public :
2010-03-28 17:58:21 +00:00
C4Network2ResType getType ( ) const { return eType ; }
bool isNull ( ) const { return eType = = NRT_Null ; }
int32_t getID ( ) const { return iID ; }
int32_t getDerID ( ) const { return iDerID ; }
bool isLoadable ( ) const { return fLoadable ; }
uint32_t getFileSize ( ) const { return iFileSize ; }
uint32_t getFileCRC ( ) const { return iFileCRC ; }
uint32_t getContentsCRC ( ) const { return iContentsCRC ; }
bool hasFileSHA ( ) const { return ! ! fHasFileSHA ; }
2009-05-08 13:28:41 +00:00
const uint8_t * getFileSHA ( ) const { return FileSHA ; }
2010-03-28 17:58:21 +00:00
const char * getFileName ( ) const { return FileName . getData ( ) ; }
uint32_t getChunkSize ( ) const { return iChunkSize ; }
uint32_t getChunkCnt ( ) const { return iFileSize & & iChunkSize ? ( iFileSize - 1 ) / iChunkSize + 1 : 0 ; }
2009-05-08 13:28:41 +00:00
2010-12-05 17:57:06 +00:00
void Set ( C4Network2ResType eType , int32_t iResID , const char * strFileName , uint32_t iContentsCRC ) ;
2010-03-28 17:58:21 +00:00
void SetID ( int32_t inID ) { iID = inID ; }
2010-03-27 16:05:02 +00:00
void SetDerived ( int32_t inDerID ) { iDerID = inDerID ; }
2009-05-08 13:28:41 +00:00
void SetLoadable ( uint32_t iSize , uint32_t iCRC ) ;
2010-03-28 17:58:21 +00:00
void SetFileSHA ( BYTE * pSHA ) { memcpy ( FileSHA , pSHA , SHA_DIGEST_LENGTH ) ; fHasFileSHA = true ; }
2009-05-08 13:28:41 +00:00
void Clear ( ) ;
2017-05-07 11:50:00 +00:00
void CompileFunc ( StdCompiler * pComp ) override ;
2009-05-08 13:28:41 +00:00
} ;
class C4Network2ResLoad
{
friend class C4Network2Res ;
public :
C4Network2ResLoad ( int32_t iChunk , int32_t iByClient ) ;
~ C4Network2ResLoad ( ) ;
protected :
// chunk download data
int32_t iChunk ;
time_t Timestamp ;
int32_t iByClient ;
// list (C4Network2Res)
C4Network2ResLoad * pNext ;
public :
2010-03-28 17:58:21 +00:00
int32_t getChunk ( ) const { return iChunk ; }
int32_t getByClient ( ) const { return iByClient ; }
2009-05-08 13:28:41 +00:00
2010-03-28 17:58:21 +00:00
C4Network2ResLoad * Next ( ) const { return pNext ; }
2009-05-08 13:28:41 +00:00
bool CheckTimeout ( ) ;
} ;
class C4Network2ResChunkData : public C4PacketBase
{
public :
C4Network2ResChunkData ( ) ;
C4Network2ResChunkData ( const C4Network2ResChunkData & Data2 ) ;
2017-05-07 11:50:00 +00:00
~ C4Network2ResChunkData ( ) override ;
2009-05-08 13:28:41 +00:00
C4Network2ResChunkData & operator = ( const C4Network2ResChunkData & Data2 ) ;
protected :
2017-05-07 11:50:00 +00:00
int32_t iChunkCnt { 0 } , iPresentChunkCnt { 0 } ;
2009-05-08 13:28:41 +00:00
// present chunk ranges
struct ChunkRange { int32_t Start , Length ; ChunkRange * Next ; } ;
2017-05-07 11:50:00 +00:00
ChunkRange * pChunkRanges { nullptr } ;
int32_t iChunkRangeCnt { 0 } ;
2009-05-08 13:28:41 +00:00
public :
2010-03-28 17:58:21 +00:00
int32_t getChunkCnt ( ) const { return iChunkCnt ; }
int32_t getPresentChunkCnt ( ) const { return iPresentChunkCnt ; }
int32_t getPresentPercent ( ) const { return iPresentChunkCnt * 100 / iChunkCnt ; }
bool isComplete ( ) const { return iPresentChunkCnt = = iChunkCnt ; }
2009-05-08 13:28:41 +00:00
void SetIncomplete ( int32_t iChunkCnt ) ;
void SetComplete ( int32_t iChunkCnt ) ;
void AddChunk ( int32_t iChunk ) ;
void AddChunkRange ( int32_t iStart , int32_t iLength ) ;
void Merge ( const C4Network2ResChunkData & Data2 ) ;
void Clear ( ) ;
int32_t GetChunkToRetrieve ( const C4Network2ResChunkData & Available , int32_t iLoadingCnt , int32_t * pLoading ) const ;
protected :
// helpers
bool MergeRanges ( ChunkRange * pRange ) ;
void GetNegative ( C4Network2ResChunkData & Target ) const ;
int32_t getPresentChunk ( int32_t iNr ) const ;
public :
2017-05-07 11:50:00 +00:00
void CompileFunc ( StdCompiler * pComp ) override ;
2009-05-08 13:28:41 +00:00
} ;
class C4Network2Res
{
friend class C4Network2ResList ;
friend class C4Network2ResChunk ;
public :
// helper for reference-holding
class Ref
{
public :
2017-05-07 11:50:00 +00:00
Ref ( ) = default ;
2010-03-28 17:58:21 +00:00
Ref ( C4Network2Res * pRes ) : pRes ( pRes ) { if ( pRes ) pRes - > AddRef ( ) ; }
Ref ( const Ref & rCopy ) : pRes ( rCopy . pRes ) { if ( pRes ) pRes - > AddRef ( ) ; }
2009-05-08 13:28:41 +00:00
~ Ref ( ) { Clear ( ) ; }
Ref & operator = ( C4Network2Res * pnRes ) { Set ( pnRes ) ; return * this ; }
Ref & operator = ( const Ref & rCopy ) { Set ( rCopy . pRes ) ; return * this ; }
private :
2017-05-07 11:50:00 +00:00
C4Network2Res * pRes { nullptr } ;
2009-05-08 13:28:41 +00:00
public :
operator C4Network2Res * ( ) const { return pRes ; }
bool operator ! ( ) const { return ! pRes ; }
C4Network2Res * operator - > ( ) const { return pRes ; }
2016-11-02 23:58:02 +00:00
void Clear ( ) { if ( pRes ) pRes - > DelRef ( ) ; pRes = nullptr ; }
2010-03-28 17:58:21 +00:00
void Set ( C4Network2Res * pnRes ) { if ( pRes = = pnRes ) return ; Clear ( ) ; pRes = pnRes ; if ( pRes ) pRes - > AddRef ( ) ; }
2009-05-08 13:28:41 +00:00
} ;
C4Network2Res ( C4Network2ResList * pnParent ) ;
~ C4Network2Res ( ) ;
protected :
// core, chunk data
C4Network2ResCore Core ;
C4Network2ResChunkData Chunks ; // (only valid while loading)
bool fDirty ;
// local file data
2010-03-27 16:05:02 +00:00
CStdCSec FileCSec ;
2009-05-08 13:28:41 +00:00
char szFile [ _MAX_PATH + 1 ] , szStandalone [ _MAX_PATH + 1 ] ;
bool fTempFile , fStandaloneFailed ;
// references
2017-03-23 16:03:16 +00:00
std : : atomic_long iRefCnt ;
2009-05-08 13:28:41 +00:00
bool fRemoved ;
// being load?
int32_t iLastReqTime ;
// loading
bool fLoading ;
struct ClientChunks { C4Network2ResChunkData Chunks ; int32_t ClientID ; ClientChunks * Next ; }
2010-03-28 17:58:21 +00:00
* pCChunks ;
2009-05-08 13:28:41 +00:00
time_t iDiscoverStartTime ;
C4Network2ResLoad * pLoads ;
int32_t iLoadCnt ;
// list (C4Network2ResList)
C4Network2Res * pNext ;
C4Network2ResList * pParent ;
public :
C4Network2ResType getType ( ) const { return Core . getType ( ) ; }
const C4Network2ResCore & getCore ( ) const { return Core ; }
2010-03-28 17:58:21 +00:00
bool isDirty ( ) const { return fDirty ; }
bool isAnonymous ( ) const { return getResID ( ) = = C4NetResIDAnonymous ; }
int32_t getResID ( ) const { return Core . getID ( ) ; }
int32_t getResClient ( ) const { return Core . getID ( ) > > 16 ; }
const char * getFile ( ) const { return szFile ; }
2010-03-27 16:05:02 +00:00
CStdCSec * getFileCSec ( ) { return & FileCSec ; }
2010-03-28 17:58:21 +00:00
int32_t getLastReqTime ( ) const { return iLastReqTime ; }
bool isRemoved ( ) const { return fRemoved ; }
bool isLoading ( ) const { return fLoading ; }
bool isComplete ( ) const { return ! fLoading ; }
int32_t getPresentPercent ( ) const { return fLoading ? Chunks . getPresentPercent ( ) : 100 ; }
2012-07-12 17:26:45 +00:00
bool isTempFile ( ) const { return fTempFile ; }
2009-05-08 13:28:41 +00:00
2016-11-02 23:58:02 +00:00
bool SetByFile ( const char * strFilePath , bool fTemp , C4Network2ResType eType , int32_t iResID , const char * szResName = nullptr , bool fSilent = false ) ;
bool SetByGroup ( C4Group * pGrp , bool fTemp , C4Network2ResType eType , int32_t iResID , const char * szResName = nullptr , bool fSilent = false ) ;
bool SetByCore ( const C4Network2ResCore & nCore , bool fSilent = false , const char * szAsFilename = nullptr , int32_t iRecursion = 0 ) ;
2009-05-08 13:28:41 +00:00
bool SetLoad ( const C4Network2ResCore & nCore ) ;
2010-03-27 16:05:02 +00:00
bool SetDerived ( const char * strName , const char * strFilePath , bool fTemp , C4Network2ResType eType , int32_t iDResID ) ;
2009-05-08 13:28:41 +00:00
void ChangeID ( int32_t inID ) ;
bool IsBinaryCompatible ( ) ;
bool GetStandalone ( char * pTo , int32_t iMaxL , bool fSetOfficial , bool fAllowUnloadable = false , bool fSilent = false ) ;
bool CalculateSHA ( ) ;
2010-03-27 16:05:02 +00:00
bool SaveBackFile ( ) ;
2009-05-08 13:28:41 +00:00
C4Network2Res : : Ref Derive ( ) ;
2010-03-27 16:05:02 +00:00
bool FinishDerive ( ) ;
bool FinishDerive ( const C4Network2ResCore & nCore ) ;
2009-05-08 13:28:41 +00:00
2016-11-02 23:58:02 +00:00
bool SendStatus ( C4Network2IOConnection * pTo = nullptr ) ;
2009-05-08 13:28:41 +00:00
bool SendChunk ( uint32_t iChunk , int32_t iToClient ) ;
// references
void AddRef ( ) ; void DelRef ( ) ;
// events
void OnDiscover ( C4Network2IOConnection * pBy ) ;
void OnStatus ( const C4Network2ResChunkData & rChunkData , C4Network2IOConnection * pBy ) ;
void OnChunk ( const C4Network2ResChunk & rChunk ) ;
bool DoLoad ( ) ;
bool NeedsDiscover ( ) ;
C4Group * OpenAsGrp ( ) const ;
void Remove ( ) ;
void Clear ( ) ;
protected :
int32_t OpenFileRead ( ) ; int32_t OpenFileWrite ( ) ;
void StartNewLoads ( ) ;
bool StartLoad ( int32_t iFromClient , const C4Network2ResChunkData & Chunks ) ;
void EndLoad ( ) ;
void ClearLoad ( ) ;
void RemoveLoad ( C4Network2ResLoad * pLoad ) ;
void RemoveCChunks ( ClientChunks * pChunks ) ;
bool OptimizeStandalone ( bool fSilent ) ;
} ;
class C4Network2ResChunk : public C4PacketBase
{
public :
C4Network2ResChunk ( ) ;
2017-05-07 11:50:00 +00:00
~ C4Network2ResChunk ( ) override ;
2009-05-08 13:28:41 +00:00
protected :
int32_t iResID ;
uint32_t iChunk ;
StdBuf Data ;
public :
2010-03-28 17:58:21 +00:00
int32_t getResID ( ) const { return iResID ; }
uint32_t getChunkNr ( ) const { return iChunk ; }
2009-05-08 13:28:41 +00:00
bool Set ( C4Network2Res * pRes , uint32_t iChunk ) ;
bool AddTo ( C4Network2Res * pRes , C4Network2IO * pIO ) const ;
2017-05-07 11:50:00 +00:00
void CompileFunc ( StdCompiler * pComp ) override ;
2009-05-08 13:28:41 +00:00
} ;
class C4Network2ResList : protected CStdCSecExCallback // run by network thread
{
friend class C4Network2Res ;
friend class C4Network2 ;
public :
C4Network2ResList ( ) ;
2017-05-07 11:50:00 +00:00
~ C4Network2ResList ( ) override ;
2009-05-08 13:28:41 +00:00
protected :
2017-05-07 11:50:00 +00:00
C4Network2Res * pFirst { nullptr } ;
2009-05-08 13:28:41 +00:00
CStdCSecEx ResListCSec ;
CStdCSec ResListAddCSec ;
2017-05-07 11:50:00 +00:00
int32_t iClientID { - 1 } , iNextResID ;
2009-05-08 13:28:41 +00:00
CStdCSec ResIDCSec ;
// timings
2017-05-07 11:50:00 +00:00
int32_t iLastDiscover { 0 } , iLastStatus { 0 } ;
2009-05-08 13:28:41 +00:00
// object used for network i/o
2017-05-07 11:50:00 +00:00
C4Network2IO * pIO { nullptr } ;
2009-05-08 13:28:41 +00:00
public :
// initialization
bool Init ( int32_t iClientID , C4Network2IO * pIOClass ) ; // by main thread
void SetLocalID ( int32_t iClientID ) ; // by both
protected :
int32_t nextResID ( ) ; // by main thread
C4Network2Res * getRes ( int32_t iResID ) ; // by both
C4Network2Res * getRes ( const char * szFile , bool fLocalOnly ) ; // by both
public :
2012-10-21 20:20:43 +00:00
// returns referenced resource ptrs
2009-05-08 13:28:41 +00:00
C4Network2Res : : Ref getRefRes ( int32_t iResID ) ; // by both
C4Network2Res : : Ref getRefRes ( const char * szFile , bool fLocalOnly = false ) ; // by both
C4Network2Res : : Ref getRefNextRes ( int32_t iResID ) ; // by both
void Add ( C4Network2Res * pRes ) ; // by both
2016-11-02 23:58:02 +00:00
C4Network2Res : : Ref AddByFile ( const char * strFilePath , bool fTemp , C4Network2ResType eType , int32_t iResID = - 1 , const char * szResName = nullptr , bool fAllowUnloadable = false ) ; // by both
C4Network2Res : : Ref AddByGroup ( C4Group * pGrp , bool fTemp , C4Network2ResType eType , int32_t iResID = - 1 , const char * szResName = nullptr , bool fAllowUnloadable = false ) ; // by both
2009-05-08 13:28:41 +00:00
C4Network2Res : : Ref AddByCore ( const C4Network2ResCore & Core , bool fLoad = true ) ; // by main thread
C4Network2Res : : Ref AddLoad ( const C4Network2ResCore & Core ) ; // by main thread
void RemoveAtClient ( int32_t iClientID ) ; // by main thread
void Clear ( ) ; // by main thread
2016-11-02 23:58:02 +00:00
bool SendDiscover ( C4Network2IOConnection * pTo = nullptr ) ; // by both
2009-05-08 13:28:41 +00:00
void OnClientConnect ( C4Network2IOConnection * pConn ) ; // by main thread
// interface for C4Network2IO
void HandlePacket ( char cStatus , const C4PacketBase * pPacket , C4Network2IOConnection * pConn ) ;
void OnTimer ( ) ;
// CStdCSecExCallback
2017-05-07 11:50:00 +00:00
void OnShareFree ( CStdCSecEx * pCSec ) override ;
2009-05-08 13:28:41 +00:00
// for C4Network2Res
C4Network2IO * getIOClass ( ) { return pIO ; }
protected :
void OnResComplete ( C4Network2Res * pRes ) ;
// misc
bool CreateNetworkFolder ( ) ;
bool FindTempResFileName ( const char * szFilename , char * pTarget ) ;
} ;
// * Packets *
class C4PacketResStatus : public C4PacketBase
{
public :
C4PacketResStatus ( ) ;
C4PacketResStatus ( int32_t iResID , const C4Network2ResChunkData & nChunks ) ;
protected :
int32_t iResID ;
C4Network2ResChunkData Chunks ;
public :
2010-03-28 17:58:21 +00:00
int32_t getResID ( ) const { return iResID ; }
2009-05-08 13:28:41 +00:00
const C4Network2ResChunkData & getChunks ( ) const { return Chunks ; }
2017-05-07 11:50:00 +00:00
void CompileFunc ( StdCompiler * pComp ) override ;
2009-05-08 13:28:41 +00:00
} ;
class C4PacketResDiscover : public C4PacketBase
{
public :
C4PacketResDiscover ( ) ;
protected :
2017-05-07 11:50:00 +00:00
int32_t iDisIDs [ 16 ] , iDisIDCnt { 0 } ;
2009-05-08 13:28:41 +00:00
public :
2010-03-28 17:58:21 +00:00
int32_t getDisIDCnt ( ) const { return iDisIDCnt ; }
int32_t getDisID ( int32_t i ) const { return iDisIDs [ i ] ; }
2009-05-08 13:28:41 +00:00
bool isIDPresent ( int32_t iID ) const ;
bool AddDisID ( int32_t iID ) ;
2017-05-07 11:50:00 +00:00
void CompileFunc ( StdCompiler * pComp ) override ;
2009-05-08 13:28:41 +00:00
} ;
class C4PacketResRequest : public C4PacketBase
{
public :
C4PacketResRequest ( int32_t iID = - 1 , int32_t iChunk = - 1 ) ;
protected :
int32_t iReqID , iReqChunk ;
public :
2010-03-28 17:58:21 +00:00
int32_t getReqID ( ) const { return iReqID ; }
2009-05-08 13:28:41 +00:00
int32_t getReqChunk ( ) const { return iReqChunk ; }
2017-05-07 11:50:00 +00:00
void CompileFunc ( StdCompiler * pComp ) override ;
2009-05-08 13:28:41 +00:00
} ;
# endif // INC_C4Network2Res