/src/network/C4Network2Res.h
C++ Header | 450 lines | 309 code | 98 blank | 43 comment | 10 complexity | 901bf33f2ab00b8332983c1a5e7a3d30 MD5 | raw file
Possible License(s): WTFPL, 0BSD, LGPL-2.1, CC-BY-3.0
1/*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2004-2007 Peter Wortmann
5 * Copyright (c) 2005 Sven Eberhardt
6 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
7 *
8 * Portions might be copyrighted by other authors who have contributed
9 * to OpenClonk.
10 *
11 * Permission to use, copy, modify, and/or distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
14 * See isc_license.txt for full license and disclaimer.
15 *
16 * "Clonk" is a registered trademark of Matthes Bender.
17 * See clonk_trademark_license.txt for full license.
18 */
19// network ressource: data needed for the game (scenario, plr files, definitions...)
20
21#ifndef INC_C4Network2Res
22#define INC_C4Network2Res
23
24#include <StdSync.h>
25
26#include <openssl/sha.h>
27
28const uint32_t C4NetResChunkSize = 10U * 1024U;
29
30const int32_t C4NetResDiscoverTimeout = 10, // (s)
31 C4NetResDiscoverInterval = 1, // (s)
32 C4NetResStatusInterval = 1, // (s)
33 C4NetResMaxLoad = 5,
34 C4NetResLoadTimeout = 60, // (s)
35 C4NetResDeleteTime = 60, // (s)
36 C4NetResMaxBigicon = 20; // maximum size, in KB, of bigicon
37
38const int32_t C4NetResIDAnonymous = -2;
39
40enum C4Network2ResType
41{
42 NRT_Null=0,
43 NRT_Scenario,
44 NRT_Dynamic,
45 NRT_Player,
46 NRT_Definitions,
47 NRT_System,
48 NRT_Material,
49};
50
51const StdEnumEntry<C4Network2ResType> C4Network2ResType_EnumMap[] =
52{
53 { "Scenario", NRT_Scenario },
54 { "Dynamic", NRT_Dynamic },
55 { "Player", NRT_Player },
56 { "Definitions", NRT_Definitions },
57 { "System", NRT_System },
58 { "Material", NRT_Material },
59};
60
61// damn circular dependencies
62#include "C4PacketBase.h"
63#include "C4Network2IO.h"
64class C4Network2ResList;
65class C4Network2ResChunk;
66
67// classes
68class C4Network2ResCore : public C4PacketBase
69{
70public:
71 C4Network2ResCore();
72
73protected:
74 C4Network2ResType eType;
75 int32_t iID, iDerID;
76 StdCopyStrBuf FileName, Author;
77 bool fLoadable;
78 uint32_t iFileSize, iFileCRC, iContentsCRC;
79 uint8_t fHasFileSHA;
80 uint8_t FileSHA[SHA_DIGEST_LENGTH];
81 uint32_t iChunkSize;
82
83public:
84 C4Network2ResType getType() const { return eType; }
85 bool isNull() const { return eType == NRT_Null; }
86 int32_t getID() const { return iID; }
87 int32_t getDerID() const { return iDerID; }
88 bool isLoadable() const { return fLoadable; }
89 uint32_t getFileSize() const { return iFileSize; }
90 uint32_t getFileCRC() const { return iFileCRC; }
91 uint32_t getContentsCRC()const { return iContentsCRC; }
92 bool hasFileSHA() const { return !!fHasFileSHA; }
93 const uint8_t*getFileSHA() const { return FileSHA; }
94 const char * getFileName() const { return FileName.getData(); }
95 const char * getAuthor() const { return Author.getData(); }
96 uint32_t getChunkSize() const { return iChunkSize; }
97 uint32_t getChunkCnt() const { return iFileSize && iChunkSize ? (iFileSize - 1) / iChunkSize + 1 : 0; }
98
99 void Set(C4Network2ResType eType, int32_t iResID, const char *strFileName, uint32_t iContentsCRC, const char *szAutor);
100 void SetID(int32_t inID) { iID = inID; }
101 void SetDerived(int32_t inDerID) { iDerID = inDerID; }
102 void SetLoadable(uint32_t iSize, uint32_t iCRC);
103 void SetFileSHA(BYTE *pSHA) { memcpy(FileSHA, pSHA, SHA_DIGEST_LENGTH); fHasFileSHA = true; }
104 void Clear();
105
106 virtual void CompileFunc(StdCompiler *pComp);
107
108};
109
110class C4Network2ResLoad
111{
112 friend class C4Network2Res;
113public:
114 C4Network2ResLoad(int32_t iChunk, int32_t iByClient);
115 ~C4Network2ResLoad();
116
117protected:
118 // chunk download data
119 int32_t iChunk;
120 time_t Timestamp;
121 int32_t iByClient;
122
123 // list (C4Network2Res)
124 C4Network2ResLoad *pNext;
125
126public:
127 int32_t getChunk() const { return iChunk; }
128 int32_t getByClient() const { return iByClient; }
129
130 C4Network2ResLoad *Next() const { return pNext; }
131
132 bool CheckTimeout();
133
134};
135
136class C4Network2ResChunkData : public C4PacketBase
137{
138public:
139 C4Network2ResChunkData();
140 C4Network2ResChunkData(const C4Network2ResChunkData &Data2);
141 ~C4Network2ResChunkData();
142
143 C4Network2ResChunkData &operator =(const C4Network2ResChunkData &Data2);
144protected:
145 int32_t iChunkCnt, iPresentChunkCnt;
146
147 // present chunk ranges
148 struct ChunkRange { int32_t Start, Length; ChunkRange *Next; };
149 ChunkRange *pChunkRanges;
150 int32_t iChunkRangeCnt;
151
152public:
153 int32_t getChunkCnt() const { return iChunkCnt; }
154 int32_t getPresentChunkCnt() const { return iPresentChunkCnt; }
155 int32_t getPresentPercent() const { return iPresentChunkCnt * 100 / iChunkCnt; }
156 bool isComplete() const { return iPresentChunkCnt == iChunkCnt; }
157
158 void SetIncomplete(int32_t iChunkCnt);
159 void SetComplete(int32_t iChunkCnt);
160
161 void AddChunk(int32_t iChunk);
162 void AddChunkRange(int32_t iStart, int32_t iLength);
163 void Merge(const C4Network2ResChunkData &Data2);
164
165 void Clear();
166
167 int32_t GetChunkToRetrieve(const C4Network2ResChunkData &Available, int32_t iLoadingCnt, int32_t *pLoading) const;
168
169protected:
170 // helpers
171 bool MergeRanges(ChunkRange *pRange);
172 void GetNegative(C4Network2ResChunkData &Target) const;
173 int32_t getPresentChunk(int32_t iNr) const;
174
175public:
176 virtual void CompileFunc(StdCompiler *pComp);
177};
178
179class C4Network2Res
180{
181 friend class C4Network2ResList;
182 friend class C4Network2ResChunk;
183public:
184
185 // helper for reference-holding
186 class Ref
187 {
188 public:
189 Ref() : pRes(NULL) { }
190 Ref(C4Network2Res *pRes) : pRes(pRes) { if(pRes) pRes->AddRef(); }
191 Ref(const Ref &rCopy) : pRes(rCopy.pRes) { if(pRes) pRes->AddRef(); }
192 ~Ref() { Clear(); }
193 Ref &operator = (C4Network2Res *pnRes) { Set(pnRes); return *this; }
194 Ref &operator = (const Ref &rCopy) { Set(rCopy.pRes); return *this; }
195 private:
196 C4Network2Res *pRes;
197 public:
198 operator C4Network2Res *() const { return pRes; }
199 bool operator ! () const { return !pRes; }
200 C4Network2Res * operator ->() const { return pRes; }
201 void Clear() { if(pRes) pRes->DelRef(); pRes = NULL; }
202 void Set(C4Network2Res *pnRes) { if(pRes == pnRes) return; Clear(); pRes = pnRes; if(pRes) pRes->AddRef(); }
203 };
204
205 C4Network2Res(C4Network2ResList *pnParent);
206 ~C4Network2Res();
207
208protected:
209 // core, chunk data
210 C4Network2ResCore Core;
211 C4Network2ResChunkData Chunks; // (only valid while loading)
212 bool fDirty;
213
214 // local file data
215 CStdCSec FileCSec;
216 char szFile[_MAX_PATH + 1], szStandalone[_MAX_PATH + 1];
217 bool fTempFile, fStandaloneFailed;
218
219 // references
220 long iRefCnt;
221 bool fRemoved;
222
223 // being load?
224 int32_t iLastReqTime;
225
226 // loading
227 bool fLoading;
228 struct ClientChunks { C4Network2ResChunkData Chunks; int32_t ClientID; ClientChunks *Next; }
229 *pCChunks;
230 time_t iDiscoverStartTime;
231 C4Network2ResLoad *pLoads;
232 int32_t iLoadCnt;
233
234 // list (C4Network2ResList)
235 C4Network2Res *pNext;
236 C4Network2ResList *pParent;
237
238public:
239 C4Network2ResType getType() const { return Core.getType(); }
240 const C4Network2ResCore &getCore() const { return Core; }
241 bool isDirty() const { return fDirty; }
242 bool isAnonymous() const { return getResID() == C4NetResIDAnonymous; }
243 int32_t getResID() const { return Core.getID(); }
244 int32_t getResClient() const { return Core.getID() >> 16; }
245 const char *getFile() const { return szFile; }
246 CStdCSec *getFileCSec() { return &FileCSec; }
247 int32_t getLastReqTime()const { return iLastReqTime; }
248 bool isRemoved() const { return fRemoved; }
249 bool isLoading() const { return fLoading; }
250 bool isComplete() const { return !fLoading; }
251 int32_t getPresentPercent() const { return fLoading ? Chunks.getPresentPercent() : 100; }
252
253 bool SetByFile(const char *strFilePath, bool fTemp, C4Network2ResType eType, int32_t iResID, const char *szResName = NULL, bool fSilent = false);
254 bool SetByGroup(C4Group *pGrp, bool fTemp, C4Network2ResType eType, int32_t iResID, const char *szResName = NULL, bool fSilent = false);
255 bool SetByCore(const C4Network2ResCore &nCore, bool fSilent = false, const char *szAsFilename = NULL, int32_t iRecursion=0);
256 bool SetLoad(const C4Network2ResCore &nCore);
257
258 bool SetDerived(const char *strName, const char *strFilePath, bool fTemp, C4Network2ResType eType, int32_t iDResID);
259
260 void ChangeID(int32_t inID);
261
262 bool IsBinaryCompatible();
263 bool GetStandalone(char *pTo, int32_t iMaxL, bool fSetOfficial, bool fAllowUnloadable = false, bool fSilent = false);
264 bool CalculateSHA();
265
266 bool SaveBackFile();
267 C4Network2Res::Ref Derive();
268 bool FinishDerive();
269 bool FinishDerive(const C4Network2ResCore &nCore);
270
271 bool SendStatus(C4Network2IOConnection *pTo = NULL);
272 bool SendChunk(uint32_t iChunk, int32_t iToClient);
273
274 // references
275 void AddRef(); void DelRef();
276
277 // events
278 void OnDiscover(C4Network2IOConnection *pBy);
279 void OnStatus(const C4Network2ResChunkData &rChunkData, C4Network2IOConnection *pBy);
280 void OnChunk(const C4Network2ResChunk &rChunk);
281 bool DoLoad();
282
283 bool NeedsDiscover();
284
285 C4Group *OpenAsGrp() const;
286
287 void Remove();
288 void Clear();
289
290protected:
291 int32_t OpenFileRead(); int32_t OpenFileWrite();
292
293 void StartNewLoads();
294 bool StartLoad(int32_t iFromClient, const C4Network2ResChunkData &Chunks);
295 void EndLoad();
296 void ClearLoad();
297
298 void RemoveLoad(C4Network2ResLoad *pLoad);
299 void RemoveCChunks(ClientChunks *pChunks);
300
301 bool OptimizeStandalone(bool fSilent);
302
303};
304
305class C4Network2ResChunk : public C4PacketBase
306{
307public:
308 C4Network2ResChunk();
309 ~C4Network2ResChunk();
310
311protected:
312 int32_t iResID;
313 uint32_t iChunk;
314 StdBuf Data;
315
316public:
317 int32_t getResID() const { return iResID; }
318 uint32_t getChunkNr() const { return iChunk; }
319
320 bool Set(C4Network2Res *pRes, uint32_t iChunk);
321 bool AddTo(C4Network2Res *pRes, C4Network2IO *pIO) const;
322
323 virtual void CompileFunc(StdCompiler *pComp);
324};
325
326class C4Network2ResList : protected CStdCSecExCallback // run by network thread
327{
328 friend class C4Network2Res;
329 friend class C4Network2;
330public:
331 C4Network2ResList();
332 virtual ~C4Network2ResList();
333
334protected:
335
336 C4Network2Res *pFirst;
337 CStdCSecEx ResListCSec;
338 CStdCSec ResListAddCSec;
339
340 int32_t iClientID, iNextResID;
341 CStdCSec ResIDCSec;
342
343 // timings
344 int32_t iLastDiscover, iLastStatus;
345
346 // object used for network i/o
347 C4Network2IO *pIO;
348
349public:
350
351 // initialization
352 bool Init(int32_t iClientID, C4Network2IO *pIOClass); // by main thread
353 void SetLocalID(int32_t iClientID); // by both
354
355protected:
356 int32_t nextResID(); // by main thread
357
358 C4Network2Res *getRes(int32_t iResID); // by both
359 C4Network2Res *getRes(const char *szFile, bool fLocalOnly); // by both
360
361public:
362 // returns referenced ressource ptrs
363 C4Network2Res::Ref getRefRes(int32_t iResID); // by both
364 C4Network2Res::Ref getRefRes(const char *szFile, bool fLocalOnly = false); // by both
365 C4Network2Res::Ref getRefNextRes(int32_t iResID); // by both
366
367 void Add(C4Network2Res *pRes); // by both
368 C4Network2Res::Ref AddByFile(const char *strFilePath, bool fTemp, C4Network2ResType eType, int32_t iResID = -1, const char *szResName = NULL, bool fAllowUnloadable = false); // by both
369 C4Network2Res::Ref AddByGroup(C4Group *pGrp, bool fTemp, C4Network2ResType eType, int32_t iResID = -1, const char *szResName = NULL, bool fAllowUnloadable = false); // by both
370 C4Network2Res::Ref AddByCore(const C4Network2ResCore &Core, bool fLoad = true); // by main thread
371 C4Network2Res::Ref AddLoad(const C4Network2ResCore &Core); // by main thread
372
373 void RemoveAtClient(int32_t iClientID); // by main thread
374 void Clear(); // by main thread
375
376 bool SendDiscover(C4Network2IOConnection *pTo = NULL); // by both
377 void OnClientConnect(C4Network2IOConnection *pConn); // by main thread
378
379 // interface for C4Network2IO
380 void HandlePacket(char cStatus, const C4PacketBase *pPacket, C4Network2IOConnection *pConn);
381 void OnTimer();
382
383 // CStdCSecExCallback
384 void OnShareFree(CStdCSecEx *pCSec);
385
386 // for C4Network2Res
387 C4Network2IO *getIOClass() { return pIO; }
388
389protected:
390 void OnResComplete(C4Network2Res *pRes);
391
392 // misc
393 bool CreateNetworkFolder();
394 bool FindTempResFileName(const char *szFilename, char *pTarget);
395
396};
397
398// * Packets *
399
400class C4PacketResStatus : public C4PacketBase
401{
402public:
403 C4PacketResStatus();
404 C4PacketResStatus(int32_t iResID, const C4Network2ResChunkData &nChunks);
405
406protected:
407 int32_t iResID;
408 C4Network2ResChunkData Chunks;
409
410public:
411 int32_t getResID() const { return iResID; }
412 const C4Network2ResChunkData &getChunks() const { return Chunks; }
413
414 virtual void CompileFunc(StdCompiler *pComp);
415};
416
417class C4PacketResDiscover : public C4PacketBase
418{
419public:
420 C4PacketResDiscover();
421
422protected:
423 int32_t iDisIDs[16], iDisIDCnt;
424
425public:
426 int32_t getDisIDCnt() const { return iDisIDCnt; }
427 int32_t getDisID(int32_t i) const { return iDisIDs[i]; }
428 bool isIDPresent(int32_t iID) const;
429
430 bool AddDisID(int32_t iID);
431
432 virtual void CompileFunc(StdCompiler *pComp);
433};
434
435class C4PacketResRequest : public C4PacketBase
436{
437public:
438 C4PacketResRequest(int32_t iID = -1, int32_t iChunk = -1);
439
440protected:
441 int32_t iReqID, iReqChunk;
442
443public:
444 int32_t getReqID() const { return iReqID; }
445 int32_t getReqChunk() const { return iReqChunk; }
446
447 virtual void CompileFunc(StdCompiler *pComp);
448};
449
450#endif // INC_C4Network2Res