1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 #ifndef INC_C4Network2
17 #define INC_C4Network2
18 
19 #include "control/C4Control.h"
20 #include "control/C4GameParameters.h"
21 #include "gui/C4Gui.h"
22 #include "network/C4NetIO.h"
23 #include "network/C4Network2Client.h"
24 #include "network/C4Network2IO.h"
25 #include "network/C4Network2Players.h"
26 #include "network/C4Network2Res.h"
27 
28 // standard ports
29 const int16_t C4NetStdPortTCP = 11112,
30               C4NetStdPortUDP = 11113,
31               C4NetStdPortDiscovery = 11114,
32               C4NetStdPortRefServer = 11111,
33               C4NetStdPortPuncher = 11115,
34               C4NetStdPortHTTP = 80;
35 
36 // resource retrieve wait timeout
37 const int C4NetResRetrieveTimeout = 100000; // (ms)
38 
39 // client (de)activation
40 const int C4NetActivationReqInterval = 5000, // (ms)
41           C4NetMaxBehind4Activation = 20, // (ticks)
42           C4NetDeactivationDelay = 500; // (ticks)
43 
44 // client chase
45 const unsigned int C4NetChaseTargetUpdateInterval = 5; // (s)
46 
47 // reference
48 const unsigned int C4NetReferenceUpdateInterval = 120; // (s)
49 const unsigned int C4NetMinLeagueUpdateInterval = 1; // (s)
50 
51 // voting
52 const unsigned int C4NetVotingTimeout = 10; // (s)
53 const unsigned int C4NetMinVotingInterval = 120; // (s)
54 
55 // streaming
56 const size_t C4NetStreamingMinBlockSize = 10 * 1024;
57 const size_t C4NetStreamingMaxBlockSize = 20 * 1024;
58 const int C4NetStreamingInterval = 30; // (s)
59 
60 enum C4NetGameState
61 {
62 	GS_None,    // network not active
63 	GS_Init,    // connecting to host, waiting for join data
64 	GS_Lobby,   // lobby mode
65 	GS_Pause,   // game paused
66 	GS_Go     // game running
67 };
68 
69 class C4Network2Status : public C4PacketBase
70 {
71 public:
72 	C4Network2Status();
73 
74 protected:
75 	C4NetGameState eState{GS_None};
76 	int32_t iCtrlMode;
77 	int32_t iTargetCtrlTick{-1};
78 
79 public:
getState()80 	C4NetGameState  getState()            const { return eState; }
getCtrlMode()81 	int32_t         getCtrlMode()         const { return iCtrlMode; }
getTargetCtrlTick()82 	int32_t         getTargetCtrlTick()   const { return iTargetCtrlTick; }
83 	const char     *getStateName()        const;
84 	const char     *getDescription()      const;
85 
isEnabled()86 	bool            isEnabled()     const { return eState != GS_None; }
isLobbyActive()87 	bool            isLobbyActive() const { return eState == GS_Lobby; }
isPastLobby()88 	bool            isPastLobby()   const { return eState  > GS_Lobby; }
isPaused()89 	bool            isPaused()      const { return eState == GS_Pause; }
isRunning()90 	bool            isRunning()     const { return eState == GS_Go; }
91 
92 	void Set(C4NetGameState eState, int32_t iTargetCtrlTick);
93 	void SetCtrlMode(int32_t iCtrlMode);
94 	void SetTargetTick(int32_t iTargetCtrlTick);
95 	void Clear();
96 
97 	void CompileFunc(StdCompiler *pComp, bool fReference);
98 	void CompileFunc(StdCompiler *pComp) override;
99 };
100 
101 class C4Network2 : private C4ApplicationSec1Timer
102 {
103 	friend class C4Network2IO;
104 public:
105 	C4Network2();
106 	~C4Network2() override;
107 
108 public:
109 	// network i/o class
110 	C4Network2IO NetIO;
111 
112 	// resource list
113 	C4Network2ResList ResList;
114 
115 	// client list
116 	C4Network2ClientList Clients;
117 
118 	// player list
119 	C4Network2Players Players;
120 
121 	// game status
122 	C4Network2Status Status;
123 
124 protected:
125 
126 	// role
127 	bool fHost;
128 
129 	// options
130 	bool fAllowJoin{false}, fAllowObserve;
131 
132 	// join resource
133 	C4Network2ResCore ResDynamic;
134 
135 	// resources
136 	int32_t iDynamicTick{-1};
137 	bool fDynamicNeeded{false};
138 
139 	// game status flags
140 	bool fStatusAck{false}, fStatusReached{false};
141 	bool fChasing{false};
142 
143 	// control
144 	class C4GameControlNetwork *pControl{nullptr};
145 
146 	// lobby
147 	C4GameLobby::MainDlg *pLobby{nullptr};
148 	bool fLobbyRunning{false};
149 	C4GameLobby::Countdown *pLobbyCountdown{nullptr};
150 
151 	// master server used
152 	StdCopyStrBuf MasterServerAddress;
153 
154 	// clients
155 	int32_t iNextClientID{0};
156 
157 	// chase
158 	uint32_t iLastChaseTargetUpdate{0};
159 
160 	// time of last activation request.
161 	C4TimeMilliseconds tLastActivateRequest;
162 
163 	// reference
164 	uint32_t iLastReferenceUpdate{0};
165 	uint32_t iLastLeagueUpdate{0}, iLeagueUpdateDelay;
166 	bool fLeagueEndSent;
167 
168 	// league
169 	class C4LeagueClient *pLeagueClient{nullptr};
170 
171 	// game password
172 	StdStrBuf sPassword;
173 
174 	// connection failed because password needed?
175 	bool fWrongPassword;
176 
177 	// delayed activation request?
178 	bool fDelayedActivateReq{false};
179 
180 	// voting
181 	C4Control Votes;
182 	class C4VoteDialog *pVoteDialog{nullptr};
183 	bool fPausedForVote{false};
184 	time_t iVoteStartTime, iLastOwnVoting{0};
185 
186 	// streaming
187 	bool fStreaming{false};
188 	time_t iLastStreamAttempt;
189 	C4Record *pStreamedRecord;
190 	StdBuf StreamingBuf;
191 	z_stream StreamCompressor;
192 
193 	class C4Network2HTTPClient *pStreamer;
194 	unsigned int iCurrentStreamAmount, iCurrentStreamPosition;
195 
196 	// puncher
197 	C4NetpuncherID NetpuncherGameID;
198 	StdCopyStrBuf NetpuncherAddr;
199 
200 public:
201 
202 	// data access
isEnabled()203 	bool isEnabled()    const { return Status.isEnabled(); }
isLobbyActive()204 	bool isLobbyActive()const { return Status.isLobbyActive(); }
isPastLobby()205 	bool isPastLobby()  const { return Status.isPastLobby(); }
isRunning()206 	bool isRunning()    const { return Status.isRunning() && isStatusAck(); }
isPaused()207 	bool isPaused()     const { return Status.isPaused() && isStatusAck(); }
isPausing()208 	bool isPausing()    const { return Status.isPaused() && !fStatusAck; }
isHost()209 	bool isHost()       const { return fHost; }
isStatusAck()210 	bool isStatusAck()  const { return fStatusAck; }
211 	bool isFrozen()     const;
212 
isJoinAllowed()213 	bool isJoinAllowed() const { return fAllowJoin; }
isObservingAllowed()214 	bool isObservingAllowed() const { return fAllowObserve; }
215 
GetLobby()216 	class C4GameLobby::MainDlg *GetLobby() const { return pLobby; } // lobby publication
GetPassword()217 	const char *GetPassword() const { return sPassword.getData(); } // Oh noez, now the password is public!
isPassworded()218 	bool isPassworded() const { return !sPassword.isNull(); }
219 
220 	// initialization result type
221 	enum InitResult
222 	{
223 		IR_Success, IR_Error, IR_Fatal
224 	};
225 
226 	// initialization
227 	bool InitHost(bool fLobby);
228 	InitResult InitClient(const class C4Network2Reference &Ref, bool fObserver);
229 	InitResult InitClient(const std::vector<class C4Network2Address>& Addrs, const class C4ClientCore &HostCore, const char *szPassword = nullptr);
230 	bool DoLobby();
231 	bool Start();
232 	bool Pause();
233 	bool Sync();
234 	bool FinalInit();
235 
236 	bool RetrieveScenario(char *szScenario);
237 	C4Network2Res::Ref RetrieveRes(const C4Network2ResCore &Core, int32_t iTimeout, const char *szResName, bool fWaitForCore = false);
238 
239 	// idle processes
240 	void OnSec1Timer() override;
241 	void Execute();
242 
243 	// termination
244 	void Clear();
245 
246 	// some options
247 	bool ToggleAllowJoin();
248 	bool ToggleClientListDlg();
249 	void AllowJoin(bool fAllow);
250 	void SetAllowObserve(bool fAllow);
251 	void SetCtrlMode(int32_t iCtrlMode);
252 	void SetPassword(const char *szToPassword);
253 	StdStrBuf QueryClientPassword(); // ask client for a password; empty if user canceled
254 
255 	// interface for C4Network2IO
256 	void OnConn(C4Network2IOConnection *pConn);
257 	void OnDisconn(C4Network2IOConnection *pConn);
258 	void HandlePacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2IOConnection *pConn);
259 	void HandleLobbyPacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2IOConnection *pConn);
260 	bool HandlePuncherPacket(C4NetpuncherPacket::uptr, C4NetIO::HostAddress::AddressFamily family);
261 	void OnPuncherConnect(C4NetIO::addr_t addr);
262 
263 	// runtime join stuff
264 	void OnGameSynchronized();
265 
266 	// status
267 	void DrawStatus(C4TargetFacet &cgo);
268 
269 	// client activation
270 	void RequestActivate();
271 	void DeactivateInactiveClients(); // host
272 
273 	// league
274 	void LeagueGameEvaluate(const char *szRecordName = nullptr, const BYTE *pRecordSHA = nullptr);
275 	void LeagueSignupDisable(); // if "internet game" button is switched off in lobby: Remove from league server
276 	bool LeagueSignupEnable();  // if "internet game" button is switched on in lobby: (re)Add to league server
277 	void InvalidateReference(); // forces a recreation and re-send of the game reference in the next execution cycle
278 	bool LeaguePlrAuth(C4PlayerInfo *pInfo); // client: get authentication for a player from the league server
279 	bool LeaguePlrAuthCheck(C4PlayerInfo *pInfo); // host: check AUID of player info with league server
280 	void LeagueNotifyDisconnect(int32_t iClientID, enum C4LeagueDisconnectReason eReason); //
281 	void LeagueWaitNotBusy(); // block until league serveris no longer busy. Process update reply if last message was an update
282 	void LeagueSurrender(); // forfeit in league - just fake a disconnect
283 	void LeagueShowError(const char *szMsg); // show league error msg box in fullscreen; just log in console
284 
285 	// voting
286 	void Vote(C4ControlVoteType eType, bool fApprove = true, int32_t iData = 0);
287 	void AddVote(const C4ControlVote &Vote);
288 	C4IDPacket *GetVote(int32_t iClientID, C4ControlVoteType eType, int32_t iData);
289 	void EndVote(C4ControlVoteType eType, bool fApprove, int32_t iData);
290 	void OpenVoteDialog();
291 	void OpenSurrenderDialog(C4ControlVoteType eType, int32_t iData);
292 	void OnVoteDialogClosed();
293 
294 	// lobby countdown
295 	void StartLobbyCountdown(int32_t iCountdownTime);
296 	void AbortLobbyCountdown();
isLobbyCountDown()297 	bool isLobbyCountDown() { return pLobbyCountdown != nullptr; }
298 
299 	// streaming
getPendingStreamData()300 	size_t getPendingStreamData() const { return StreamingBuf.getSize() - StreamCompressor.avail_out; }
301 	bool isStreaming() const;
302 	bool StartStreaming(C4Record *pRecord);
303 	bool FinishStreaming();
304 	bool StopStreaming();
305 
306 	// netpuncher
307 	C4NetpuncherID::value& getNetpuncherGameID(C4NetIO::HostAddress::AddressFamily family);
getNetpuncherGameID()308 	C4NetpuncherID getNetpuncherGameID() const { return NetpuncherGameID; };
getNetpuncherAddr()309 	StdStrBuf getNetpuncherAddr() const { return NetpuncherAddr; }
310 
311 protected:
312 
313 	using C4ApplicationSec1Timer::Execute; // to avoid "virtual ... is hidden" warning
314 
315 	// net i/o initialization
316 	bool InitNetIO(bool fNoClientID, bool fHost);
317 
318 	// handling of own packets
319 	void HandleConn(const class C4PacketConn &Pkt, C4Network2IOConnection *pConn, C4Network2Client *pClient);
320 	bool CheckConn(const C4ClientCore &CCore, C4Network2IOConnection *pConn, C4Network2Client *pClient, StdStrBuf * szReply);
321 	bool HostConnect(const C4ClientCore &CCore, C4Network2IOConnection *pConn, StdStrBuf *szReply);
322 	bool Join(C4ClientCore &CCore, C4Network2IOConnection *pConn, StdStrBuf *szReply);
323 	void HandleConnRe(const class C4PacketConnRe &Pkt, C4Network2IOConnection *pConn, C4Network2Client *pClient);
324 	void HandleStatus(const C4Network2Status &nStatus);
325 	void HandleStatusAck(const C4Network2Status &nStatus, C4Network2Client *pClient);
326 	void HandleActivateReq(int32_t iTick, C4Network2Client *pClient);
327 	void HandleJoinData(const class C4PacketJoinData &rPkt);
328 
329 	// events
330 	void OnConnect(C4Network2Client *pClient, C4Network2IOConnection *pConn, const char *szMsg, bool fFirstConnection);
331 	void OnConnectFail(C4Network2IOConnection *pConn);
332 	void OnDisconnect(C4Network2Client *pClient, C4Network2IOConnection *pConn);
333 	void OnClientConnect(C4Network2Client *pClient, C4Network2IOConnection *pConn);
334 	void OnClientDisconnect(C4Network2Client *pClient);
335 
336 	void SendJoinData(C4Network2Client *pClient);
337 
338 	// resource list
339 	bool CreateDynamic(bool fInit);
340 	void RemoveDynamic();
341 
342 	// status changes
343 	bool PauseGame(bool fAutoContinue);
344 	bool ChangeGameStatus(C4NetGameState enState, int32_t iTargetCtrlTick, int32_t iCtrlMode = -1);
345 	void CheckStatusReached(bool fFromFinalInit = false);
346 	void CheckStatusAck();
347 	void OnStatusReached();
348 	void OnStatusAck();
349 
350 	// chase
351 	void UpdateChaseTarget();
352 
353 	// league
354 	bool InitLeague(bool *pCancel);
355 	void DeinitLeague();
356 	bool LeagueStart(bool *pCancel);
357 	bool LeagueUpdate();
358 	bool LeagueUpdateProcessReply();
359 	bool LeagueEnd(const char *szRecordName = nullptr, const BYTE *pRecordSHA = nullptr);
360 
361 	// streaming
362 	bool StreamIn(bool fFinish);
363 	bool StreamOut();
364 
365 	// puncher
366 	void InitPuncher();
367 
368 	// Manages delayed initial connection attempts.
369 	class InitialConnect : protected CStdTimerProc
370 	{
371 		static const uint32_t DELAY = 100; // ms to wait for each batch
372 		static const int ADDR_PER_TRY = 4; // how many connection attempts to start each time
373 
374 		const std::vector<C4Network2Address>& Addrs;
375 		std::vector<C4Network2Address>::const_iterator CurrentAddr;
376 		const C4ClientCore& HostCore;
377 		const char *Password;
378 
379 		void TryNext();
380 		void Done();
381 
382 	public:
383 		InitialConnect(const std::vector<C4Network2Address>& Addrs, const C4ClientCore& HostCore, const char *Password);
384 		~InitialConnect() override;
385 		bool Execute(int, pollfd *) override;
386 	};
387 };
388 
389 extern C4Network2 Network;
390 
391 class C4VoteDialog : public C4GUI::MessageDialog
392 {
393 public:
394 	C4VoteDialog(const char *szText, C4ControlVoteType eVoteType, int32_t iVoteData, bool fSurrender);
395 
396 private:
397 	C4ControlVoteType eVoteType;
398 	int32_t iVoteData;
399 	bool fSurrender;
400 
401 public:
getVoteType()402 	C4ControlVoteType getVoteType() const { return eVoteType; }
getVoteData()403 	int32_t getVoteData() const { return iVoteData; }
404 
405 private:
OnEnter()406 	bool OnEnter() override { UserClose(false); return true; } // the vote dialog defaults to "No" [MarkFra]
407 	void OnClosed(bool fOK) override;
408 
409 	// true for dialogs that receive full keyboard and mouse input even in shared mode
IsExclusiveDialog()410 	bool IsExclusiveDialog() override { return true; }
411 };
412 
413 // * Packets *
414 
415 class C4PacketJoinData : public C4PacketBase
416 {
417 public:
418 	C4PacketJoinData() = default;
419 
420 protected:
421 
422 	// the client ID
423 	int32_t iClientID;
424 
425 	// Dynamic data to boot
426 	C4Network2ResCore Dynamic;
427 
428 	// network status
429 	C4Network2Status GameStatus;
430 
431 	// control tick
432 	int32_t iStartCtrlTick;
433 
434 public:
435 
436 	// scenario parameter definitions (so the client can see them in the lobby)
437 	C4ScenarioParameterDefs ScenarioParameterDefs;
438 
439 	// the game parameters
440 	C4GameParameters Parameters;
441 
442 public:
getClientID()443 	const int32_t          &getClientID()       const { return iClientID; }
getDynamicCore()444 	const C4Network2ResCore&getDynamicCore()    const { return Dynamic; }
getStatus()445 	const C4Network2Status &getStatus()         const { return GameStatus; }
getStartCtrlTick()446 	int32_t                 getStartCtrlTick()  const { return iStartCtrlTick; }
447 
SetClientID(int32_t inClientID)448 	void SetClientID(int32_t inClientID) { iClientID = inClientID; }
SetGameStatus(const C4Network2Status & Status)449 	void SetGameStatus(const C4Network2Status &Status) { GameStatus = Status; }
SetDynamicCore(const C4Network2ResCore & Core)450 	void SetDynamicCore(const C4Network2ResCore &Core) { Dynamic = Core; }
SetStartCtrlTick(int32_t iTick)451 	void SetStartCtrlTick(int32_t iTick)               { iStartCtrlTick = iTick; }
452 
453 	void CompileFunc(StdCompiler *pComp) override;
454 };
455 
456 class C4PacketActivateReq : public C4PacketBase
457 {
458 public:
iTick(iTick)459 	C4PacketActivateReq(int32_t iTick = -1) : iTick(iTick) { }
460 
461 protected:
462 	int32_t iTick;
463 
464 public:
getTick()465 	int32_t getTick() const { return iTick; }
466 
467 	void CompileFunc(StdCompiler *pComp) override;
468 };
469 
470 #endif
471