AutopatcherServer.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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 The server plugin for the autopatcher. Must be running for the client to get patches.
  12. // TODO - bsdiff doesn't work for files above 100 megabytes.
  13. // See http://xdelta.org/
  14. // XDelta is GPL 2, however I could run that as a separate EXE and invoke to only transmit the delta file.
  15. // See http://pocketsoft.com/rtpatch.html
  16. // See use rdiff instead of bsdiff, or perhaps librsync
  17. // See https://code.google.com/p/open-vcdiff/
  18. // https://code.google.com/p/open-vcdiff/wiki/HowToUseOpenVcdiff
  19. // https://github.com/gtoubassi/femtozip/wiki/Sdch
  20. #ifndef __AUTOPATCHER_SERVER_H
  21. #define __AUTOPATCHER_SERVER_H
  22. #include "RakNetTypes.h"
  23. #include "Export.h"
  24. #include "PluginInterface2.h"
  25. #include "PacketPriority.h"
  26. #include "ThreadPool.h"
  27. #include "BitStream.h"
  28. #include "RakString.h"
  29. #include "FileList.h"
  30. #include "IncrementalReadInterface.h"
  31. namespace RakNet
  32. {
  33. /// Forward declarations
  34. class RakPeerInterface;
  35. struct Packet;
  36. class AutopatcherRepositoryInterface;
  37. class FileListTransfer;
  38. class RAK_DLL_EXPORT AutopatcherServerLoadNotifier
  39. {
  40. public:
  41. /// Current queue state of the autopatcher
  42. struct AutopatcherState
  43. {
  44. /// How many requests have been queued to be processed later
  45. unsigned int requestsQueued;
  46. /// How many requests are currently working (including downloading files).
  47. /// This will not normally exceed AutopatcherServer::SetMaxConurrentUsers()
  48. unsigned int requestsWorking;
  49. };
  50. /// The server only handles two types of requests - to get a change list since a certain date, or to get a patch
  51. enum RequestType
  52. {
  53. ASUMC_GET_CHANGELIST,
  54. ASUMC_GET_PATCH,
  55. };
  56. enum QueueOperation
  57. {
  58. QO_WAS_ADDED,
  59. QO_WAS_ABORTED,
  60. QO_POPPED_ONTO_TO_PROCESSING_THREAD
  61. };
  62. enum GetChangelistResult
  63. {
  64. GCR_DELETE_FILES,
  65. GCR_ADD_FILES,
  66. GCR_ADD_AND_DELETE_FILES,
  67. GCR_NOTHING_TO_DO,
  68. GCR_REPOSITORY_ERROR,
  69. };
  70. enum PatchResult
  71. {
  72. PR_NO_FILES_NEEDED_PATCHING,
  73. PR_REPOSITORY_ERROR,
  74. PR_DISALLOWED_DOWNLOADING_ORIGINAL_FILES,
  75. PR_PATCHES_WERE_SENT,
  76. PR_ABORTED_FROM_INPUT_THREAD,
  77. PR_ABORTED_FROM_DOWNLOAD_THREAD,
  78. };
  79. /// The server queues have been updated
  80. /// \param[out] remoteSystem Which system this refers to
  81. /// \param[out] requestType Either added to / removed a changelist request, or a get patch request
  82. /// \param[out] queueOperation The operation was added to the queue, removed from the queue to be processed, or removed because it was aborted
  83. /// \param[out] autopatcherState Current size of the request queue, and how many requests are working
  84. virtual void OnQueueUpdate(SystemAddress remoteSystem,
  85. AutopatcherServerLoadNotifier::RequestType requestType,
  86. AutopatcherServerLoadNotifier::QueueOperation queueOperation,
  87. AutopatcherServerLoadNotifier::AutopatcherState *autopatcherState)
  88. {(void) remoteSystem; (void) requestType; (void) queueOperation; (void) autopatcherState;}
  89. virtual void OnGetChangelistCompleted(
  90. SystemAddress remoteSystem,
  91. AutopatcherServerLoadNotifier::GetChangelistResult getChangelistResult,
  92. AutopatcherServerLoadNotifier::AutopatcherState *autopatcherState)
  93. {(void) remoteSystem; (void) autopatcherState;}
  94. /// A file transfer has completed, or was not necessary
  95. /// \param[out] remoteSystem Which system this refers to
  96. /// \param[out] autopatcherState Current size of the request queue, and how many requests are working
  97. virtual void OnGetPatchCompleted(SystemAddress remoteSystem,
  98. AutopatcherServerLoadNotifier::PatchResult patchResult,
  99. AutopatcherServerLoadNotifier::AutopatcherState *autopatcherState)
  100. {(void) remoteSystem; (void) patchResult; (void) autopatcherState;};
  101. };
  102. /// \brief Sample implementation of AutopatcherServerLoadNotifier using printf
  103. class RAK_DLL_EXPORT AutopatcherServerLoadNotifier_Printf : public AutopatcherServerLoadNotifier
  104. {
  105. public:
  106. virtual void OnQueueUpdate(SystemAddress remoteSystem,
  107. AutopatcherServerLoadNotifier::RequestType requestType,
  108. AutopatcherServerLoadNotifier::QueueOperation queueOperation,
  109. AutopatcherServerLoadNotifier::AutopatcherState *autopatcherState);
  110. virtual void OnGetChangelistCompleted(
  111. SystemAddress remoteSystem,
  112. AutopatcherServerLoadNotifier::GetChangelistResult getChangelistResult,
  113. AutopatcherServerLoadNotifier::AutopatcherState *autopatcherState);
  114. virtual void OnGetPatchCompleted(SystemAddress remoteSystem,
  115. AutopatcherServerLoadNotifier::PatchResult patchResult,
  116. AutopatcherServerLoadNotifier::AutopatcherState *autopatcherState);
  117. };
  118. /// \brief The server plugin for the autopatcher. Must be running for the client to get patches.
  119. class RAK_DLL_EXPORT AutopatcherServer : public PluginInterface2 , public ThreadDataInterface, FileListProgress, IncrementalReadInterface
  120. {
  121. public:
  122. // Constructor
  123. AutopatcherServer();
  124. // Destructor
  125. ~AutopatcherServer();
  126. /// DO THIS FIRST
  127. /// Implement to start the worker threads.
  128. /// Before this is called, no queries will be performed
  129. /// When this is called, AllocAutopatcherRepositoryInterface will be called with \a repositoryAllocationParameters
  130. /// The system works in three phases.
  131. /// 1. Get change list since a given date. This uses one of the worker threads.
  132. /// 2. If either running a full scan, or files have changed since a given date, get the list of patches. This uses one of the worker threads and does an intensive comparison of the hashes the client has vs. the files in the database
  133. /// 3. If the total amount of data to be sent exceeds DATABASE_READ_CHUNK_SIZE, defined in the cpp file, then the database will be read from incrementally during this download phase. This uses an sql connection object, which may or may not be also in use by one of the threads.
  134. /// If you have more sql connections than threads, this tends to prevent the same connection from being used to incrementally read files for a downloader, and to be used in a worker thread.
  135. /// \param[in] numThreads Number of processing threads, which handles the CPU intensive tasks of generating a patch list and comparing files
  136. /// \param[in] numSQLConnections Number of SQL connection objects passed to \a sqlConnectionPtrArray. Must be greater than or equal to numThreads
  137. /// \param[in] sqlConnectionPtrArray List of pointers to AutopatcherRepositoryInterface. C++ note: Don't just cast a derived class array, you need to take the pointer address of each item
  138. void StartThreads(int numThreads, int numSQLConnections, AutopatcherRepositoryInterface **sqlConnectionPtrArray);
  139. /// Load the most recent patch in memory and keep it there
  140. /// This can take a lot of memory, but greatly speeds up serving patches, since disk access is not incurred
  141. /// \param[in] applicationName 0 means all, otherwise the name of the application to cache
  142. void CacheMostRecentPatch(const char *applicationName);
  143. /// What parameters to use for the RakPeerInterface::Send() call when uploading files.
  144. /// \param[in] _priority See RakPeerInterface::Send()
  145. /// \param[in] _orderingChannel See RakPeerInterface::Send()
  146. void SetUploadSendParameters(PacketPriority _priority, char _orderingChannel);
  147. /// This plugin has a dependency on the FileListTransfer plugin, which it uses to actually send the files.
  148. /// So you need an instance of that plugin registered with RakPeerInterface, and a pointer to that interface should be passed here.
  149. /// \param[in] flt A pointer to a registered instance of FileListTransfer
  150. void SetFileListTransferPlugin(FileListTransfer *flt);
  151. /// This is the maximum number of users the patcher will service at one time (generally about equal to the number of downloads at once)
  152. /// If this limit is exceeded, the request packet will be put into a queue and serviced when slots are available
  153. /// Defaults to 0 (unlimited)
  154. /// \param[in] maxConcurrentUsers Pass 0 for unlimited, otherwise the max users to serve at once
  155. void SetMaxConurrentUsers(unsigned int _maxConcurrentUsers);
  156. /// \return Returns what was passed to SetMaxConurrentUsers();
  157. unsigned int GetMaxConurrentUsers(void) const;
  158. /// Set a callback to get notifications of when user requests are queued and processed
  159. /// This is primarily of use to load balance the server
  160. /// \param[in] asumc An externally allocated instance of AutopatcherServerLoadNotifier. Pass 0 to disable.
  161. void SetLoadManagementCallback(AutopatcherServerLoadNotifier *asumc);
  162. /// Set whether or not the client can download files that were never modified, that they do not have
  163. /// Defaults to true
  164. /// Set to false to disallow downloading the entire game through the autopatcher. In this case, the user must have a copy of the game through other means (such as a CD install)
  165. /// \param[in] allow True to allow downloading original game files, false to disallow
  166. void SetAllowDownloadOfOriginalUnmodifiedFiles(bool allow);
  167. /// Clear buffered input and output
  168. void Clear(void);
  169. /// \internal For plugin handling
  170. virtual void OnAttach(void);
  171. /// \internal For plugin handling
  172. virtual void OnDetach(void);;
  173. /// \internal For plugin handling
  174. virtual void Update(void);
  175. /// \internal For plugin handling
  176. virtual PluginReceiveResult OnReceive(Packet *packet);
  177. /// \internal For plugin handling
  178. virtual void OnShutdown(void);
  179. /// \internal For plugin handling
  180. virtual void OnStartup(RakPeerInterface *peer);
  181. /// \internal For plugin handling
  182. virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
  183. struct ThreadData
  184. {
  185. AutopatcherServer *server;
  186. RakNet::RakString applicationName;
  187. double lastUpdateDate;
  188. SystemAddress systemAddress;
  189. FileList *clientList;
  190. unsigned short setId;
  191. };
  192. /// \deprecated
  193. struct ResultTypeAndBitstream
  194. {
  195. ResultTypeAndBitstream() {patchList=0; deletedFiles=0; addedOrModifiedFilesWithHashData=0;}
  196. int resultType;
  197. SystemAddress systemAddress;
  198. RakNet::BitStream bitStream1;
  199. RakNet::BitStream bitStream2;
  200. FileList *patchList;
  201. FileList *deletedFiles, *addedOrModifiedFilesWithHashData;
  202. // bool fatalError;
  203. int resultCode; // 1 = success, 0 = unknown error, -1 = failed allowDownloadOfOriginalUnmodifiedFiles check
  204. unsigned short setId;
  205. double currentDate;
  206. enum
  207. {
  208. GET_CHANGELIST_SINCE_DATE,
  209. GET_PATCH,
  210. } operation;
  211. };
  212. protected:
  213. friend AutopatcherServer::ResultTypeAndBitstream* GetChangelistSinceDateCB(AutopatcherServer::ThreadData pap, bool *returnOutput, void* perThreadData);
  214. friend AutopatcherServer::ResultTypeAndBitstream* GetPatchCB(AutopatcherServer::ThreadData pap, bool *returnOutput, void* perThreadData);
  215. PluginReceiveResult OnGetChangelistSinceDate(Packet *packet);
  216. PluginReceiveResult OnGetPatch(Packet *packet);
  217. void OnGetChangelistSinceDateInt(Packet *packet);
  218. void OnGetPatchInt(Packet *packet);
  219. void* PerThreadFactory(void *context);
  220. void PerThreadDestructor(void* factoryResult, void *context);
  221. void RemoveFromThreadPool(SystemAddress systemAddress);
  222. virtual unsigned int GetFilePart( const char *filename, unsigned int startReadBytes, unsigned int numBytesToRead, void *preallocatedDestination, FileListNodeContext context);
  223. //AutopatcherRepositoryInterface *repository;
  224. FileListTransfer *fileListTransfer;
  225. PacketPriority priority;
  226. char orderingChannel;
  227. // The point of the threadPool is so that SQL queries, which are blocking, happen in the thread and don't slow down the rest of the application
  228. // The threadPool has a queue for incoming processing requests. As systems disconnect their pending requests are removed from the list.
  229. ThreadPool<ThreadData, ResultTypeAndBitstream*> threadPool;
  230. SimpleMutex connectionPoolMutex;
  231. DataStructures::Queue<AutopatcherRepositoryInterface *> connectionPool;
  232. // How many users are currently patching
  233. // unsigned int patchingUserCount;
  234. SimpleMutex patchingUsersMutex;
  235. DataStructures::List<SystemAddress> patchingUsers;
  236. bool IncrementPatchingUserCount(SystemAddress sa);
  237. bool DecrementPatchingUserCount(SystemAddress sa);
  238. bool PatchingUserLimitReached(void) const;
  239. virtual void OnFilePushesComplete( SystemAddress systemAddress, unsigned short setID );
  240. virtual void OnSendAborted( SystemAddress systemAddress );
  241. unsigned int maxConcurrentUsers;
  242. // If maxConcurrentUsers is exceeded, then incoming requests are put into this queue
  243. DataStructures::Queue<Packet *> userRequestWaitingQueue;
  244. void AddToWaitingQueue(Packet *packet);
  245. Packet *AbortOffWaitingQueue(void);
  246. Packet *PopOffWaitingQueue(void);
  247. AutopatcherServerLoadNotifier *loadNotifier;
  248. void CallPacketCallback(Packet *packet, AutopatcherServerLoadNotifier::QueueOperation queueOperation);
  249. void CallPatchCompleteCallback(const SystemAddress &systemAddress, AutopatcherServerLoadNotifier::PatchResult patchResult);
  250. RakNet::RakString cache_appName;
  251. FileList cache_patchedFiles;
  252. FileList cache_addedFiles;
  253. FileList cache_addedOrModifiedFileHashes;
  254. FileList cache_deletedFiles;
  255. double cache_minTime, cache_maxTime;
  256. bool cacheLoaded;
  257. bool allowDownloadOfOriginalUnmodifiedFiles;
  258. };
  259. } // namespace RakNet
  260. #endif
粤ICP备19079148号