OpenClonk
C4Network2Reference.cpp
Go to the documentation of this file.
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 #include "C4Include.h"
18 
19 #include "C4Version.h"
20 #include "control/C4RoundResults.h"
21 #include "game/C4Application.h"
22 
23 // *** C4Network2Reference
24 
26  : GameMode(), NetpuncherGameID(C4NetpuncherID())
27 {
28 
29 }
30 
32 
34 {
35  source = ip;
36  if (iAddrCnt < C4ClientMaxAddr)
37  Addrs[++iAddrCnt].SetAddr(ip);
38 }
39 
41 {
42  // Copy all game parameters
43  Parameters = ::Game.Parameters;
44 
45  // Discard player resources (we don't want these infos in the reference)
46  // Add league performance (but only after game end)
47  C4ClientPlayerInfos *pClientInfos; C4PlayerInfo *pPlayerInfo;
48  int32_t i, j;
49  for (i = 0; (pClientInfos = Parameters.PlayerInfos.GetIndexedInfo(i)); i++)
50  for (j = 0; (pPlayerInfo = pClientInfos->GetPlayerInfo(j)); j++)
51  {
52  pPlayerInfo->DiscardResource();
53  if(::Game.GameOver)
54  pPlayerInfo->SetLeaguePerformance(::Game.RoundResults.GetLeaguePerformance(pPlayerInfo->GetID()));
55  }
56 
57  // Special additional information in reference
58  Icon = ::Game.C4S.Head.Icon;
59  Title.CopyValidated(::Game.ScenarioTitle);
60  GameMode = ::Game.C4S.Game.Mode;
61  GameStatus = ::Network.Status;
62  Time = ::Game.Time;
63  Frame = ::Game.FrameCounter;
64  StartTime = ::Game.StartTime;
65  LeaguePerformance = ::Game.RoundResults.GetLeaguePerformance();
66  Comment = Config.Network.Comment;
67  JoinAllowed = ::Network.isJoinAllowed();
68  ObservingAllowed = ::Network.isObservingAllowed();
69  PasswordNeeded = ::Network.isPassworded();
70  IsEditor = !!::Application.isEditor;
71  NetpuncherGameID = ::Network.getNetpuncherGameID();
72  NetpuncherAddr = ::Network.getNetpuncherAddr();
73  Statistics = ::Game.RoundResults.GetStatistics();
74  Game.Set();
75 
76  // Addresses
77  C4Network2Client *pLocalNetClient = ::Game.Clients.getLocal()->getNetClient();
78  iAddrCnt = pLocalNetClient->getAddrCnt();
79  for (i = 0; i < iAddrCnt; i++)
80  Addrs[i] = pLocalNetClient->getAddr(i);
81 
82 }
83 
85 {
86  // Sort all addresses with zero IP to back of list
87  int iSortAddrCnt = iAddrCnt;
88  for (int i = 0; i < iSortAddrCnt; i++)
89  if (Addrs[i].isIPNull())
90  {
91  C4Network2Address Addr = Addrs[i];
92  for (int j = i + 1; j < iAddrCnt; j++)
93  Addrs[j - 1] = Addrs[j];
94  Addrs[iAddrCnt - 1] = Addr;
95  // Correct position
96  i--; iSortAddrCnt--;
97  }
98 }
99 
101 {
102  pComp->Value(mkNamingAdapt(Icon, "Icon", 0));
103  pComp->Value(mkNamingAdapt(Title, "Title", "No title"));
104  pComp->Value(mkNamingAdapt(mkParAdapt(GameMode, StdCompiler::RCT_IdtfAllowEmpty), "GameMode", ""));
105  pComp->Value(mkParAdapt(GameStatus, true));
106  pComp->Value(mkNamingAdapt(Time, "Time", 0));
107  pComp->Value(mkNamingAdapt(Frame, "Frame", 0));
108  pComp->Value(mkNamingAdapt(StartTime, "StartTime", 0));
109  pComp->Value(mkNamingAdapt(LeaguePerformance, "LeaguePerformance",0));
110  pComp->Value(mkNamingAdapt(Comment, "Comment", ""));
111  pComp->Value(mkNamingAdapt(JoinAllowed, "JoinAllowed", true));
112  pComp->Value(mkNamingAdapt(ObservingAllowed, "ObservingAllowed", true));
113  pComp->Value(mkNamingAdapt(PasswordNeeded, "PasswordNeeded", false));
114  pComp->Value(mkNamingAdapt(IsEditor, "IsEditor", false));
115  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iAddrCnt), "AddressCount", 0));
116  iAddrCnt = std::min<uint8_t>(C4ClientMaxAddr, iAddrCnt);
117  pComp->Value(mkNamingAdapt(mkArrayAdapt(Addrs, iAddrCnt, C4Network2Address()), "Address"));
118  pComp->Value(mkNamingAdapt(Game.sEngineName, "Game", "None"));
119  pComp->Value(mkNamingAdapt(mkArrayAdaptDM(Game.iVer,0),"Version" ));
120  pComp->Value(mkNamingAdapt(OfficialServer, "OfficialServer", false));
121  pComp->Value(mkNamingAdapt(NetpuncherGameID, "NetpuncherID", C4NetpuncherID(), false, false));
122  pComp->Value(mkNamingAdapt(NetpuncherAddr, "NetpuncherAddr", "", false, false));
123  pComp->Value(mkNamingAdapt(mkParAdapt(Statistics, StdCompiler::RCT_All), "Statistics", "", false, false));
124 
125  pComp->Value(Parameters);
126 }
127 
128 int32_t C4Network2Reference::getSortOrder() const // Don't go over 100, because that's for the masterserver...
129 {
130  C4GameVersion verThis;
131  int iOrder = 0;
132  // Official server
133  if (isOfficialServer() && !Config.Network.UseAlternateServer) iOrder += 50;
134  // Joinable
135  if (isJoinAllowed() && (getGameVersion() == verThis)) iOrder += 25;
136  // League game
137  if (Parameters.isLeague()) iOrder += 5;
138  // In lobby
139  if (getGameStatus().isLobbyActive()) iOrder += 3;
140  // No password needed
141  if (!isPasswordNeeded()) iOrder += 1;
142  // Done
143  return iOrder;
144 }
145 
147 {
148  if (GameMode.getLength() > 0)
149  {
150  // Prefer to derive string from game mode
151  return FormatString("%s: %s", LoadResStr("IDS_MENU_CPGOALS"), GameMode.getData());
152  }
153  else
154  {
155  // If not defined, fall back to goal string
156  return Parameters.GetGameGoalString();
157  }
158 }
159 
160 
161 // *** C4Network2RefServer
162 
164 
166 {
167  Clear();
168 }
169 
171 {
173  delete pReference; pReference = nullptr;
174 }
175 
177 {
178  CStdLock RefLock(&RefCSec);
179  delete pReference; pReference = pNewReference;
180 }
181 
183 {
184  // Just append the packet
185  rOutBuf.Append(rPacket);
186 }
187 
188 size_t C4Network2RefServer::UnpackPacket(const StdBuf &rInBuf, const C4NetIO::addr_t &addr)
189 {
190  const char *pData = getBufPtr<char>(rInBuf);
191  // Check for complete header
192  const char *pHeaderEnd = strstr(pData, "\r\n\r\n");
193  if (!pHeaderEnd)
194  return 0;
195  // Check method (only GET is allowed for now)
196  if (!SEqual2(pData, "GET "))
197  {
198  RespondNotImplemented(addr, "Method not implemented");
199  return rInBuf.getSize();
200  }
201  // Check target
202  // TODO
203  RespondReference(addr);
204  return rInBuf.getSize();
205 }
206 
207 void C4Network2RefServer::RespondNotImplemented(const C4NetIO::addr_t &addr, const char *szMessage)
208 {
209  // Send the message
210  StdStrBuf Data = FormatString("HTTP/1.0 501 %s\r\n\r\n", szMessage);
211  Send(C4NetIOPacket(Data.getData(), Data.getLength(), false, addr));
212  // Close the connection
213  Close(addr);
214 }
215 
216 void C4Network2RefServer::RespondReference(const C4NetIO::addr_t &addr)
217 {
218  CStdLock RefLock(&RefCSec);
219  // Pack
220  StdStrBuf PacketData = DecompileToBuf<StdCompilerINIWrite>(mkNamingPtrAdapt(pReference, "Reference"));
221  // Create header
222  StdStrBuf Header = FormatString(
223  "HTTP/1.1 200 Found\r\n"
224  "Content-Length: %lu\r\n"
225  "Content-Type: text/plain; charset=UTF-8\r\n"
226  "Server: " C4ENGINENAME "/" C4VERSION "\r\n"
227  "\r\n",
228  static_cast<unsigned long>(PacketData.getLength()));
229  // Send back
230  Send(C4NetIOPacket(Header, Header.getLength(), false, addr));
231  Send(C4NetIOPacket(PacketData, PacketData.getLength(), false, addr));
232  // Close the connection
233  Close(addr);
234 }
235 
236 // *** C4Network2UpdateClient
237 
239 {
240  // Perform an Query query
241  return Query(nullptr, false);
242 }
243 
245 {
246  // Sanity check
247  if (isBusy() || !isSuccess()) return false;
248  // Parse response
249  try
250  {
251  CompileFromBuf<StdCompilerINIRead>(mkNamingAdapt(
252  mkNamingAdapt(mkParAdapt(*pUpdateURL, StdCompiler::RCT_All), "UpdateURL", ""),
253  C4ENGINENAME), ResultString);
254  }
255  catch (StdCompiler::Exception *pExc)
256  {
257  SetError(pExc->Msg.getData());
258  return false;
259  }
260  // done; version OK!
261  return true;
262 }
263 
265 {
266  // Sanity check
267  if (isBusy() || !isSuccess()) return false;
268  // Parse response
269  try
270  {
271  CompileFromBuf<StdCompilerINIRead>(mkNamingAdapt(
272  mkNamingAdapt(mkParAdapt(*pVersion, StdCompiler::RCT_All), "Version", ""),
273  C4ENGINENAME), ResultString);
274  }
275  catch (StdCompiler::Exception *pExc)
276  {
277  SetError(pExc->Msg.getData());
278  return false;
279  }
280  // done; version OK!
281  return true;
282 }
283 
284 // *** C4Network2RefClient
285 
287 {
288  // Perform an Query query
289  return Query(nullptr, false);
290 }
291 
292 bool C4Network2RefClient::GetReferences(C4Network2Reference **&rpReferences, int32_t &rRefCount)
293 {
294  // Sanity check
295  if (isBusy() || !isSuccess()) return false;
296  // local update test
297  try
298  {
299  // Create compiler
300  StdCompilerINIRead Comp;
301  Comp.setInput(ResultString);
302  Comp.Begin();
303  // Read reference count
304  Comp.Value(mkNamingCountAdapt(rRefCount, "Reference"));
305  // Create reference array and initialize
306  rpReferences = new C4Network2Reference *[rRefCount];
307  for (int i = 0; i < rRefCount; i++)
308  rpReferences[i] = nullptr;
309  // Get references
310  Comp.Value(mkNamingAdapt(mkArrayAdaptMap(rpReferences, rRefCount, mkPtrAdaptNoNull<C4Network2Reference>), "Reference"));
311  mkPtrAdaptNoNull<C4Network2Reference>(*rpReferences);
312  // Done
313  Comp.End();
314  }
315  catch (StdCompiler::Exception *pExc)
316  {
317  SetError(pExc->Msg.getData());
318  return false;
319  }
320  // Set source ip
321  for (int i = 0; i < rRefCount; i++)
322  rpReferences[i]->SetSourceAddress(getServerAddress());
323  // Done
324  ResetError();
325  return true;
326 }
327 
C4Config Config
Definition: C4Config.cpp:930
C4Application Application
Definition: C4Globals.cpp:44
C4Network2 Network
Definition: C4Globals.cpp:53
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
const int32_t C4ClientMaxAddr
bool SEqual2(const char *szStr1, const char *szStr2)
Definition: Standard.cpp:204
StdArrayDefaultAdapt< T, D > mkArrayAdaptDM(T(&array)[size], const D &rDefault)
Definition: StdAdaptors.h:392
StdArrayAdapt< T > mkArrayAdapt(T *pArray, int iSize)
Definition: StdAdaptors.h:336
StdArrayAdapt< T, M > mkArrayAdaptMap(T *pArray, int iSize, M &&map)
Definition: StdAdaptors.h:340
StdPtrAdapt< T > mkNamingPtrAdapt(T *&rpObj, const char *szNaming)
Definition: StdAdaptors.h:636
StdIntPackAdapt< T > mkIntPackAdapt(T &rVal)
Definition: StdAdaptors.h:791
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:490
StdNamingCountAdapt< int_t > mkNamingCountAdapt(int_t &iCount, const char *szName)
Definition: StdAdaptors.h:1008
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:92
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
C4PlayerInfo * GetPlayerInfo(int32_t iIndex) const
C4ConfigNetwork Network
Definition: C4Config.h:259
ValidatedStdCopyStrBuf< C4InVal::VAL_Comment > Comment
Definition: C4Config.h:146
int32_t UseAlternateServer
Definition: C4Config.h:152
bool isLeague() const
StdStrBuf GetGameGoalString() const
C4PlayerInfoList PlayerInfos
void SetError(const char *strnError)
Definition: C4HTTP.h:80
bool isSuccess() const
Definition: C4HTTP.h:88
void ResetError()
Definition: C4HTTP.h:97
bool Query(const StdBuf &Data, bool fBinary)
Definition: C4HTTP.cpp:158
const C4NetIO::addr_t & getServerAddress() const
Definition: C4HTTP.h:95
StdCopyStrBuf ResultString
Definition: C4HTTP.h:78
bool isBusy() const
Definition: C4HTTP.h:86
bool Send(const C4NetIOPacket &rPacket) override
Definition: C4NetIO.cpp:1310
bool Close() override
Definition: C4NetIO.cpp:857
void SetAddr(C4NetIO::addr_t naddr)
const C4Network2Address & getAddr(int32_t i) const
int32_t getAddrCnt() const
C4Network2Status Status
Definition: C4Network2.h:122
C4NetpuncherID::value & getNetpuncherGameID(C4NetIO::HostAddress::AddressFamily family)
bool isJoinAllowed() const
Definition: C4Network2.h:213
StdStrBuf getNetpuncherAddr() const
Definition: C4Network2.h:309
bool isPassworded() const
Definition: C4Network2.h:218
bool isObservingAllowed() const
Definition: C4Network2.h:214
bool GetReferences(C4Network2Reference **&rpReferences, int32_t &rRefCount)
size_t UnpackPacket(const StdBuf &rInBuf, const C4NetIO::addr_t &addr) override
void SetReference(C4Network2Reference *pReference)
void PackPacket(const C4NetIOPacket &rPacket, StdBuf &rOutBuf) override
C4GameParameters Parameters
bool isPasswordNeeded() const
int32_t getSortOrder() const
void CompileFunc(StdCompiler *pComp)
const C4GameVersion & getGameVersion() const
bool isOfficialServer() const
void SetSourceAddress(const C4NetIO::EndpointAddress &ip)
StdStrBuf getGameGoalString() const
C4Network2Status getGameStatus() const
bool GetVersion(StdStrBuf *pVersion)
bool GetUpdateURL(StdStrBuf *pUpdateURL)
int32_t GetID() const
Definition: C4PlayerInfo.h:194
void SetLeaguePerformance(int32_t iNewPerf)
Definition: C4PlayerInfo.h:137
void DiscardResource()
C4ClientPlayerInfos * GetIndexedInfo(int32_t iIndex) const
Definition: C4PlayerInfo.h:358
Definition: StdBuf.h:30
size_t getSize() const
Definition: StdBuf.h:101
void Append(const void *pnData, size_t inSize)
Definition: StdBuf.h:254
void Value(const T &rStruct)
Definition: StdCompiler.h:161
@ RCT_IdtfAllowEmpty
Definition: StdCompiler.h:140
void End() override
void setInput(const InT &In)
Definition: StdCompiler.h:630
void Begin() override
const char * getData() const
Definition: StdBuf.h:442
size_t getLength() const
Definition: StdBuf.h:445
int32_t iVer[2]
Definition: C4GameVersion.h:27
ValidatedStdCopyStrBuf< C4InVal::VAL_NameAllowEmpty > sEngineName
Definition: C4GameVersion.h:26
void Set(const char *szEngine=C4ENGINENAME, int32_t iVer1=C4XVER1, int32_t iVer2=C4XVER2)
Definition: C4GameVersion.h:31
void CopyValidated(const char *szFromVal)