PHPDirectoryServer2.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. /// \file
  11. /// \brief Contains WebGameList, a client for communicating with a HTTP list of game servers
  12. ///
  13. /// Creative Commons Licensees are subject to the
  14. /// license found at
  15. /// http://creativecommons.org/licenses/by-nc/2.5/
  16. /// Single application licensees are subject to the license found at
  17. /// http://www.jenkinssoftware.com/SingleApplicationLicense.html
  18. /// Custom license users are subject to the terms therein.
  19. /// GPL license users are subject to the GNU General Public
  20. /// License as published by the Free Software Foundation
  21. #include "PHPDirectoryServer2.h"
  22. #include "HTTPConnection.h"
  23. #include "RakSleep.h"
  24. #include "RakString.h"
  25. #include "RakNetTypes.h"
  26. #include "GetTime.h"
  27. #include "RakAssert.h"
  28. #include <cstring>
  29. #include <cstdlib>
  30. #include <cstdio>
  31. #include "Itoa.h"
  32. // Column with this header contains the name of the game, passed to UploadTable()
  33. static const char *GAME_NAME_COMMAND="__GAME_NAME";
  34. // Column with this header contains the port of the game, passed to UploadTable()
  35. static const char *GAME_PORT_COMMAND="__GAME_PORT";
  36. // Column with this header contains the IP address of the game, passed to UploadTable()
  37. static const char *SYSTEM_ADDRESS_COMMAND="_System_Address";
  38. // Returned from the PHP server indicating when this row was last updated.
  39. static const char *LAST_UPDATE_COMMAND="__SEC_AFTER_EPOCH_SINCE_LAST_UPDATE";
  40. using namespace RakNet;
  41. using namespace DataStructures;
  42. PHPDirectoryServer2::PHPDirectoryServer2()
  43. : nextRepost(0)
  44. {
  45. Map<RakString, RakString>::IMPLEMENT_DEFAULT_COMPARISON();
  46. }
  47. PHPDirectoryServer2::~PHPDirectoryServer2()
  48. {
  49. }
  50. void PHPDirectoryServer2::Init(HTTPConnection *_http, const char *_path)
  51. {
  52. http=_http;
  53. pathToPHP=_path;
  54. }
  55. void PHPDirectoryServer2::SetField( RakNet::RakString columnName, RakNet::RakString value )
  56. {
  57. if (columnName.IsEmpty())
  58. return;
  59. if (columnName==GAME_NAME_COMMAND ||
  60. columnName==GAME_PORT_COMMAND ||
  61. columnName==LAST_UPDATE_COMMAND)
  62. {
  63. RakAssert("PHPDirectoryServer2::SetField attempted to set reserved column name" && 0);
  64. return;
  65. }
  66. fields.Set(columnName, value);
  67. }
  68. unsigned int PHPDirectoryServer2::GetFieldCount(void) const
  69. {
  70. return fields.Size();
  71. }
  72. void PHPDirectoryServer2::GetField(unsigned int index, RakNet::RakString &columnName, RakNet::RakString &value)
  73. {
  74. RakAssert(index < fields.Size());
  75. columnName=fields.GetKeyAtIndex(index);
  76. value=fields[index];
  77. }
  78. void PHPDirectoryServer2::SetFields(DataStructures::Table *table)
  79. {
  80. ClearFields();
  81. unsigned columnIndex, rowIndex;
  82. DataStructures::Table::Row *row;
  83. for (rowIndex=0; rowIndex < table->GetRowCount(); rowIndex++)
  84. {
  85. row = table->GetRowByIndex(rowIndex, 0);
  86. for (columnIndex=0; columnIndex < table->GetColumnCount(); columnIndex++)
  87. {
  88. SetField( table->ColumnName(columnIndex), row->cells[columnIndex]->ToString(table->GetColumnType(columnIndex)) );
  89. }
  90. }
  91. }
  92. void PHPDirectoryServer2::ClearFields(void)
  93. {
  94. fields.Clear();
  95. nextRepost=0;
  96. }
  97. void PHPDirectoryServer2::UploadTable(RakNet::RakString uploadPassword, RakNet::RakString gameName, unsigned short gamePort, bool autoRepost)
  98. {
  99. gameNameParam=gameName;
  100. gamePortParam=gamePort;
  101. currentOperation="";
  102. currentOperation="?query=upload&uploadPassword=";
  103. currentOperation+=uploadPassword;
  104. SendOperation();
  105. if (autoRepost)
  106. nextRepost=RakNet::GetTimeMS()+50000;
  107. else
  108. nextRepost=0;
  109. }
  110. void PHPDirectoryServer2::DownloadTable(RakNet::RakString downloadPassword)
  111. {
  112. currentOperation="?query=download&downloadPassword=";
  113. currentOperation+=downloadPassword;
  114. SendOperation();
  115. }
  116. void PHPDirectoryServer2::UploadAndDownloadTable(RakNet::RakString uploadPassword, RakNet::RakString downloadPassword, RakNet::RakString gameName, unsigned short gamePort, bool autoRepost)
  117. {
  118. gameNameParam=gameName;
  119. gamePortParam=gamePort;
  120. currentOperation="?query=upDown&downloadPassword=";
  121. currentOperation+=downloadPassword;
  122. currentOperation+="&uploadPassword=";
  123. currentOperation+=uploadPassword;
  124. SendOperation();
  125. if (autoRepost)
  126. nextRepost=RakNet::GetTimeMS()+50000;
  127. else
  128. nextRepost=0;
  129. }
  130. HTTPReadResult PHPDirectoryServer2::ProcessHTTPRead(RakNet::RakString httpRead)
  131. {
  132. const char *c = (const char*) httpRead.C_String(); // current position
  133. HTTPReadResult resultCode=HTTP_RESULT_EMPTY;
  134. lastDownloadedTable.Clear();
  135. if (*c=='\n')
  136. c++;
  137. char buff[256];
  138. int buffIndex;
  139. bool isCommand=true;
  140. DataStructures::List<RakNet::RakString> columns;
  141. DataStructures::List<RakNet::RakString> values;
  142. RakNet::RakString curString;
  143. bool isComment=false;
  144. buffIndex=0;
  145. while(c && *c)
  146. {
  147. // 3 is comment
  148. if (*c=='\003')
  149. {
  150. isComment=!isComment;
  151. c++;
  152. continue;
  153. }
  154. if (isComment)
  155. {
  156. c++;
  157. continue;
  158. }
  159. // 1 or 2 separates fields
  160. // 4 separates rows
  161. if (*c=='\001')
  162. {
  163. if (isCommand)
  164. {
  165. buff[buffIndex]=0;
  166. columns.Push(RakString::NonVariadic(buff), _FILE_AND_LINE_);
  167. isCommand=false;
  168. if (buff[0]!=0)
  169. resultCode=HTTP_RESULT_GOT_TABLE;
  170. }
  171. else
  172. {
  173. buff[buffIndex]=0;
  174. values.Push(RakString::NonVariadic(buff), _FILE_AND_LINE_);
  175. isCommand=true;
  176. }
  177. buffIndex=0;
  178. }
  179. else if (*c=='\002')
  180. {
  181. buff[buffIndex]=0;
  182. buffIndex=0;
  183. values.Push(RakString::NonVariadic(buff), _FILE_AND_LINE_);
  184. isCommand=true;
  185. PushColumnsAndValues(columns, values);
  186. columns.Clear(true, _FILE_AND_LINE_);
  187. values.Clear(true, _FILE_AND_LINE_);
  188. }
  189. else
  190. {
  191. if (buffIndex<256-1)
  192. buff[buffIndex++]=*c;
  193. }
  194. c++;
  195. }
  196. if (buff[0] && columns.Size()==values.Size()+1)
  197. {
  198. buff[buffIndex]=0;
  199. values.Push(RakString::NonVariadic(buff), _FILE_AND_LINE_);
  200. }
  201. PushColumnsAndValues(columns, values);
  202. return resultCode;
  203. }
  204. void PHPDirectoryServer2::PushColumnsAndValues(DataStructures::List<RakNet::RakString> &columns, DataStructures::List<RakNet::RakString> &values)
  205. {
  206. DataStructures::Table::Row *row=0;
  207. unsigned int i;
  208. for (i=0; i < columns.Size() && i < values.Size(); i++)
  209. {
  210. if (columns[i].IsEmpty()==false)
  211. {
  212. unsigned col = lastDownloadedTable.ColumnIndex(columns[i]);
  213. if(col == (unsigned)-1)
  214. {
  215. col = lastDownloadedTable.AddColumn(columns[i], DataStructures::Table::STRING);
  216. }
  217. if (row==0)
  218. {
  219. row = lastDownloadedTable.AddRow(lastDownloadedTable.GetAvailableRowId());
  220. }
  221. row->UpdateCell(col,values[i].C_String());
  222. }
  223. }
  224. }
  225. const DataStructures::Table *PHPDirectoryServer2::GetLastDownloadedTable(void) const
  226. {
  227. return &lastDownloadedTable;
  228. }
  229. void PHPDirectoryServer2::SendOperation(void)
  230. {
  231. RakString outgoingMessageBody;
  232. char buff[64];
  233. outgoingMessageBody += GAME_PORT_COMMAND;
  234. outgoingMessageBody += '\001';
  235. outgoingMessageBody += Itoa(gamePortParam,buff,10);
  236. outgoingMessageBody += '\001';
  237. outgoingMessageBody += GAME_NAME_COMMAND;
  238. outgoingMessageBody += '\001';
  239. outgoingMessageBody += gameNameParam;
  240. for (unsigned i = 0; i < fields.Size(); i++)
  241. {
  242. RakString value = fields[i];
  243. value.URLEncode();
  244. outgoingMessageBody += RakString("\001%s\001%s",
  245. fields.GetKeyAtIndex(i).C_String(),
  246. value.C_String());
  247. }
  248. RakString postURL;
  249. postURL+=pathToPHP;
  250. postURL+=currentOperation;
  251. http->Post(postURL.C_String(), outgoingMessageBody, "application/x-www-form-urlencoded");
  252. }
  253. void PHPDirectoryServer2::Update(void)
  254. {
  255. if (http->IsBusy())
  256. return;
  257. if (nextRepost==0 || fields.Size()==0)
  258. return;
  259. RakNet::TimeMS time = GetTimeMS();
  260. // Entry deletes itself after 60 seconds, so keep reposting if set to do so
  261. if (time > nextRepost)
  262. {
  263. nextRepost=RakNet::GetTimeMS()+50000;
  264. SendOperation();
  265. }
  266. }
粤ICP备19079148号