llcorehttpservice.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. /**
  2. * @file llcorehttpservice.cpp
  3. * @brief Internal definitions of the Http service thread
  4. *
  5. * $LicenseInfo:firstyear=2012&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2012, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "llcorehttpservice.h"
  28. #include "llcorehttpinternal.h"
  29. #include "llcorehttplibcurl.h"
  30. #include "llcorehttpoperation.h"
  31. #include "llcorehttppolicy.h"
  32. #include "llcorehttprequestqueue.h"
  33. #include "llsys.h"
  34. #include "llthread.h"
  35. #include "lltimer.h"
  36. namespace LLCore
  37. {
  38. ///////////////////////////////////////////////////////////////////////////////
  39. // This used to be in a separate llcorethread.h header within the LLCoreInt
  40. // namespace, but it is only used in this module, so I moved it here. HB
  41. ///////////////////////////////////////////////////////////////////////////////
  42. class HttpThread : public LLCoreInt::RefCounted
  43. {
  44. private:
  45. HttpThread() = delete;
  46. void operator=(const HttpThread&) = delete;
  47. void at_exit()
  48. {
  49. // The thread function has exited so we need to release our reference
  50. // to ourself so that we will be automagically cleaned up.
  51. release();
  52. }
  53. // THREAD CONTEXT
  54. void run()
  55. {
  56. // Run on other cores than the main (renderer) thread if the affinity
  57. // was set for the latter; this is a no-op for macOS. HB
  58. LLCPUInfo::setThreadCPUAffinity("HttpThread");
  59. // Take out additional reference for the at_exit handler
  60. addRef();
  61. boost::this_thread::at_thread_exit(boost::bind(&HttpThread::at_exit,
  62. this));
  63. // Run the thread function
  64. mThreadFunc(this);
  65. }
  66. protected:
  67. ~HttpThread() override
  68. {
  69. delete mThread;
  70. }
  71. public:
  72. // Constructs a thread object for concurrent execution but does not start
  73. // running. Caller receives on refcount on the thread instance. If the
  74. // thread is started, another will be taken out for the exit handler.
  75. explicit HttpThread(boost::function<void (HttpThread*)> thread_func)
  76. : LLCoreInt::RefCounted(true), // Implicit reference
  77. mThreadFunc(thread_func)
  78. {
  79. // This creates a boost thread that will call HttpThread::run on this instance
  80. // and pass it the threadfunc callable...
  81. boost::function<void()> f = boost::bind(&HttpThread::run, this);
  82. mThread = new boost::thread(f);
  83. }
  84. LL_INLINE void join()
  85. {
  86. mThread->join();
  87. }
  88. LL_INLINE bool timedJoin(S32 millis)
  89. {
  90. return mThread->timed_join(boost::posix_time::milliseconds(millis));
  91. }
  92. LL_INLINE bool joinable() const
  93. {
  94. return mThread->joinable();
  95. }
  96. // A very hostile method to force a thread to quit
  97. LL_INLINE void cancel()
  98. {
  99. boost::thread::native_handle_type thread(mThread->native_handle());
  100. #if LL_WINDOWS
  101. TerminateThread(thread, 0);
  102. #else
  103. pthread_cancel(thread);
  104. #endif
  105. }
  106. private:
  107. boost::function<void(HttpThread*)> mThreadFunc;
  108. boost::thread* mThread;
  109. };
  110. ///////////////////////////////////////////////////////////////////////////////
  111. // HttpService class proper
  112. ///////////////////////////////////////////////////////////////////////////////
  113. const HttpService::OptionDescriptor HttpService::sOptionDesc[] =
  114. { // isLong, isDynamic, isGlobal, isClass, isCallback
  115. { true, true, true, true, false }, // PO_CONNECTION_LIMIT
  116. { true, true, false, true, false }, // PO_PER_HOST_CONNECTION_LIMIT
  117. { false, false, true, false, false }, // PO_CA_PATH
  118. { false, false, true, false, false }, // PO_CA_FILE
  119. { false, true, true, false, false }, // PO_HTTP_PROXY
  120. { true, true, true, false, false }, // PO_LLPROXY
  121. { true, true, true, true, false }, // PO_TRACE
  122. { true, true, false, true, false }, // PO_ENABLE_PIPELINING
  123. { true, true, false, true, false }, // PO_THROTTLE_RATE
  124. { false, false, true, false, true } // PO_SSL_VERIFY_CALLBACK
  125. };
  126. HttpService* HttpService::sInstance = NULL;
  127. volatile HttpService::EState HttpService::sState = NOT_INITIALIZED;
  128. HttpService::HttpService()
  129. : mRequestQueue(NULL),
  130. mExitRequested(0U),
  131. mThread(NULL),
  132. mPolicy(NULL),
  133. mTransport(NULL),
  134. mLastPolicy(0)
  135. {
  136. }
  137. HttpService::~HttpService()
  138. {
  139. mExitRequested = 1U;
  140. if (sState == RUNNING)
  141. {
  142. // Trying to kill the service object with a running thread is a bit
  143. // tricky.
  144. if (mRequestQueue)
  145. {
  146. if (mRequestQueue->stopQueue())
  147. {
  148. ms_sleep(10); // Give mRequestQueue a chance to finish
  149. }
  150. }
  151. if (mThread && !mThread->timedJoin(250))
  152. {
  153. // Failed to join, expect problems ahead so do a hard termination.
  154. llwarns << "Destroying HttpService with running thread. Expect problems. Last policy: "
  155. << (U32)mLastPolicy << llendl;
  156. mThread->cancel();
  157. }
  158. }
  159. if (mRequestQueue)
  160. {
  161. mRequestQueue->release();
  162. mRequestQueue = NULL;
  163. }
  164. delete mTransport;
  165. mTransport = NULL;
  166. delete mPolicy;
  167. mPolicy = NULL;
  168. if (mThread)
  169. {
  170. mThread->release();
  171. mThread = NULL;
  172. }
  173. }
  174. void HttpService::init(HttpRequestQueue* queue)
  175. {
  176. llassert_always(!sInstance && sState == NOT_INITIALIZED);
  177. sInstance = new HttpService();
  178. queue->addRef();
  179. sInstance->mRequestQueue = queue;
  180. sInstance->mPolicy = new HttpPolicy(sInstance);
  181. sInstance->mTransport = new HttpLibcurl(sInstance);
  182. sState = INITIALIZED;
  183. }
  184. void HttpService::term()
  185. {
  186. if (sInstance)
  187. {
  188. if (sState == RUNNING && sInstance->mThread)
  189. {
  190. // Unclean termination. Thread appears to be running. We'll try to
  191. // give the worker thread a chance to cancel using the exit flag...
  192. sInstance->mExitRequested = 1U;
  193. sInstance->mRequestQueue->stopQueue();
  194. // And a little sleep
  195. for (S32 i = 0; i < 10 && sState == RUNNING; ++i)
  196. {
  197. ms_sleep(100);
  198. }
  199. }
  200. delete sInstance;
  201. sInstance = NULL;
  202. }
  203. sState = NOT_INITIALIZED;
  204. }
  205. HttpRequest::policy_t HttpService::createPolicyClass()
  206. {
  207. mLastPolicy = mPolicy->createPolicyClass();
  208. return mLastPolicy;
  209. }
  210. // Threading: callable by consumer thread *once*.
  211. void HttpService::startThread()
  212. {
  213. llassert_always(!mThread || sState == STOPPED || sState == INITIALIZED);
  214. if (mThread)
  215. {
  216. mThread->release();
  217. }
  218. // Push current policy definitions, enable policy & transport components
  219. mPolicy->start();
  220. mTransport->start(mLastPolicy + 1);
  221. mThread = new HttpThread(boost::bind(&HttpService::threadRun, this, _1));
  222. sState = RUNNING;
  223. }
  224. // Tries to find the given request handle on any of the request queues and
  225. // cancels the operation. Returns true if the request was cancelled.
  226. // Threading: callable by the worker thread.
  227. bool HttpService::cancel(HttpHandle handle)
  228. {
  229. // Request cannot be on request queue so skip that and check the policy
  230. // component's queues first
  231. bool cancelled = mPolicy->cancel(handle);
  232. if (!cancelled)
  233. {
  234. // If that did not work, check transport's.
  235. cancelled = mTransport->cancel(handle);
  236. }
  237. return cancelled;
  238. }
  239. // Threading: callable by worker thread.
  240. void HttpService::shutdown()
  241. {
  242. // Disallow future enqueue of requests
  243. mRequestQueue->stopQueue();
  244. // Cancel requests already on the request queue
  245. HttpRequestQueue::OpContainer ops;
  246. mRequestQueue->fetchAll(false, ops);
  247. for (HttpRequestQueue::OpContainer::iterator it = ops.begin(),
  248. end = ops.end();
  249. it != end; ++it)
  250. {
  251. (*it)->cancel();
  252. }
  253. ops.clear();
  254. // Shutdown transport cancelling requests, freeing resources
  255. mTransport->shutdown();
  256. // And now policy
  257. mPolicy->shutdown();
  258. }
  259. // Working thread loop-forever method. Gives time to each of the request queue,
  260. // policy layer and transport layer pieces and then either sleeps for a small
  261. // time or waits for a request to come in. Repeats until requested to stop.
  262. void HttpService::threadRun(HttpThread* thread)
  263. {
  264. boost::this_thread::disable_interruption di;
  265. int loop = REQUEST_SLEEP;
  266. while (!mExitRequested)
  267. {
  268. loop = (int)processRequestQueue((ELoopSpeed)loop);
  269. // Process ready queue issuing new requests as needed
  270. int new_loop = (int)mPolicy->processReadyQueue();
  271. loop = (std::min)(loop, new_loop);
  272. // Give libcurl some cycles
  273. new_loop = mTransport->processTransport();
  274. loop = (std::min)(loop, new_loop);
  275. // Determine whether to spin, sleep briefly or sleep for next request
  276. if (loop != (int)REQUEST_SLEEP)
  277. {
  278. ms_sleep(HTTP_SERVICE_LOOP_SLEEP_NORMAL_MS);
  279. }
  280. }
  281. shutdown();
  282. sState = STOPPED;
  283. }
  284. int HttpService::processRequestQueue(ELoopSpeed loop)
  285. {
  286. HttpRequestQueue::OpContainer ops;
  287. const bool wait_for_req = loop == REQUEST_SLEEP;
  288. mRequestQueue->fetchAll(wait_for_req, ops);
  289. while (!ops.empty())
  290. {
  291. HttpOperation::ptr_t op(ops.front());
  292. ops.erase(ops.begin());
  293. // Process operation
  294. if (!mExitRequested)
  295. {
  296. // Setup for subsequent tracing
  297. long tracing = HTTP_TRACE_OFF;
  298. mPolicy->getGlobalOptions().get(HttpRequest::PO_TRACE, &tracing);
  299. op->mTracing = llmax(op->mTracing, tracing);
  300. if (op->mTracing > HTTP_TRACE_OFF)
  301. {
  302. llinfos << "TRACE, FromRequestQueue, Handle: "
  303. << op->getHandle() << llendl;
  304. }
  305. // Stage
  306. op->stageFromRequest(this);
  307. }
  308. // Done with operation
  309. op.reset();
  310. }
  311. // Queue emptied, allow polling loop to sleep
  312. return (int)REQUEST_SLEEP;
  313. }
  314. HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt,
  315. HttpRequest::policy_t pclass,
  316. long* ret_value)
  317. {
  318. if (opt < HttpRequest::PO_CONNECTION_LIMIT || // Option must be in range
  319. opt >= HttpRequest::PO_LAST || // Ditto
  320. !sOptionDesc[opt].mIsLong || // Datatype is long
  321. // pclass in valid range
  322. (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) ||
  323. // Global setting permitted
  324. (pclass == HttpRequest::GLOBAL_POLICY_ID &&
  325. !sOptionDesc[opt].mIsGlobal) ||
  326. // Class setting permitted
  327. (pclass != HttpRequest::GLOBAL_POLICY_ID &&
  328. !sOptionDesc[opt].mIsClass))
  329. // Can always get, no dynamic check
  330. {
  331. return HttpStatus(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
  332. }
  333. HttpStatus status;
  334. if (pclass == HttpRequest::GLOBAL_POLICY_ID)
  335. {
  336. HttpPolicyGlobal& opts = mPolicy->getGlobalOptions();
  337. status = opts.get(opt, ret_value);
  338. }
  339. else
  340. {
  341. HttpPolicyClass& opts = mPolicy->getClassOptions(pclass);
  342. status = opts.get(opt, ret_value);
  343. }
  344. return status;
  345. }
  346. HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt,
  347. HttpRequest::policy_t pclass,
  348. std::string* ret_value)
  349. {
  350. HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
  351. if (opt < HttpRequest::PO_CONNECTION_LIMIT || // Option must be in range
  352. opt >= HttpRequest::PO_LAST || // Ditto
  353. sOptionDesc[opt].mIsLong || // Datatype is string
  354. // pclass in valid range
  355. (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) ||
  356. // Global setting permitted
  357. (pclass == HttpRequest::GLOBAL_POLICY_ID &&
  358. !sOptionDesc[opt].mIsGlobal) ||
  359. // Class setting permitted
  360. (pclass != HttpRequest::GLOBAL_POLICY_ID &&
  361. !sOptionDesc[opt].mIsClass))
  362. // Can always get, no dynamic check
  363. {
  364. return status;
  365. }
  366. // Only global has string values
  367. if (pclass == HttpRequest::GLOBAL_POLICY_ID)
  368. {
  369. HttpPolicyGlobal& opts = mPolicy->getGlobalOptions();
  370. status = opts.get(opt, ret_value);
  371. }
  372. return status;
  373. }
  374. HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt,
  375. HttpRequest::policy_t pclass,
  376. HttpRequest::policyCallback_t* ret_value)
  377. {
  378. HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
  379. if (opt < HttpRequest::PO_CONNECTION_LIMIT || // Option must be in range
  380. opt >= HttpRequest::PO_LAST || // Ditto
  381. sOptionDesc[opt].mIsLong || // Datatype is string
  382. // pclass in valid range
  383. (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) ||
  384. // Global setting permitted
  385. (pclass == HttpRequest::GLOBAL_POLICY_ID &&
  386. !sOptionDesc[opt].mIsGlobal) ||
  387. // Class setting permitted
  388. (pclass != HttpRequest::GLOBAL_POLICY_ID &&
  389. !sOptionDesc[opt].mIsClass))
  390. // Can always get, no dynamic check
  391. {
  392. return status;
  393. }
  394. // Only global has callback values
  395. if (pclass == HttpRequest::GLOBAL_POLICY_ID)
  396. {
  397. HttpPolicyGlobal& opts = mPolicy->getGlobalOptions();
  398. status = opts.get(opt, ret_value);
  399. }
  400. return status;
  401. }
  402. HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt,
  403. HttpRequest::policy_t pclass,
  404. long value, long* ret_value)
  405. {
  406. HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
  407. if (opt < HttpRequest::PO_CONNECTION_LIMIT || // Option must be in range
  408. opt >= HttpRequest::PO_LAST || // Ditto
  409. !sOptionDesc[opt].mIsLong || // Datatype is long
  410. // pclass in valid range
  411. (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) ||
  412. // Global setting permitted
  413. (pclass == HttpRequest::GLOBAL_POLICY_ID &&
  414. !sOptionDesc[opt].mIsGlobal) ||
  415. // Class setting permitted
  416. (pclass != HttpRequest::GLOBAL_POLICY_ID &&
  417. !sOptionDesc[opt].mIsClass) ||
  418. // Dynamic setting permitted
  419. (RUNNING == sState && ! sOptionDesc[opt].mIsDynamic))
  420. {
  421. return status;
  422. }
  423. if (pclass == HttpRequest::GLOBAL_POLICY_ID)
  424. {
  425. HttpPolicyGlobal& opts = mPolicy->getGlobalOptions();
  426. status = opts.set(opt, value);
  427. if (status && ret_value)
  428. {
  429. status = opts.get(opt, ret_value);
  430. }
  431. }
  432. else
  433. {
  434. HttpPolicyClass& opts = mPolicy->getClassOptions(pclass);
  435. status = opts.set(opt, value);
  436. if (status)
  437. {
  438. mTransport->policyUpdated(pclass);
  439. if (ret_value)
  440. {
  441. status = opts.get(opt, ret_value);
  442. }
  443. }
  444. }
  445. return status;
  446. }
  447. HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt,
  448. HttpRequest::policy_t pclass,
  449. const std::string& value,
  450. std::string* ret_value)
  451. {
  452. HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
  453. if (opt < HttpRequest::PO_CONNECTION_LIMIT || // Option must be in range
  454. opt >= HttpRequest::PO_LAST || // Ditto
  455. sOptionDesc[opt].mIsLong || // Datatype is string
  456. // pclass in valid range
  457. (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) ||
  458. // Global setting permitted
  459. (pclass == HttpRequest::GLOBAL_POLICY_ID &&
  460. !sOptionDesc[opt].mIsGlobal) ||
  461. // Class setting permitted
  462. (pclass != HttpRequest::GLOBAL_POLICY_ID &&
  463. !sOptionDesc[opt].mIsClass) ||
  464. // Dynamic setting permitted
  465. (sState == RUNNING && !sOptionDesc[opt].mIsDynamic))
  466. {
  467. return status;
  468. }
  469. // String values are always global (at this time).
  470. if (pclass == HttpRequest::GLOBAL_POLICY_ID)
  471. {
  472. HttpPolicyGlobal& opts = mPolicy->getGlobalOptions();
  473. status = opts.set(opt, value);
  474. if (status && ret_value)
  475. {
  476. status = opts.get(opt, ret_value);
  477. }
  478. }
  479. return status;
  480. }
  481. HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt,
  482. HttpRequest::policy_t pclass,
  483. HttpRequest::policyCallback_t value,
  484. HttpRequest::policyCallback_t* ret_value)
  485. {
  486. HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
  487. if (opt < HttpRequest::PO_CONNECTION_LIMIT || // Option must be in range
  488. opt >= HttpRequest::PO_LAST || // Ditto
  489. sOptionDesc[opt].mIsLong || // Datatype is string
  490. // pclass in valid range
  491. (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) ||
  492. // Global setting permitted
  493. (pclass == HttpRequest::GLOBAL_POLICY_ID &&
  494. !sOptionDesc[opt].mIsGlobal) ||
  495. // Class setting permitted
  496. (pclass != HttpRequest::GLOBAL_POLICY_ID &&
  497. !sOptionDesc[opt].mIsClass) ||
  498. // Dynamic setting permitted
  499. (sState == RUNNING && !sOptionDesc[opt].mIsDynamic))
  500. {
  501. return status;
  502. }
  503. // Callbacks values are always global (at this time).
  504. if (pclass == HttpRequest::GLOBAL_POLICY_ID)
  505. {
  506. HttpPolicyGlobal& opts = mPolicy->getGlobalOptions();
  507. status = opts.set(opt, value);
  508. if (status && ret_value)
  509. {
  510. status = opts.get(opt, ret_value);
  511. }
  512. }
  513. return status;
  514. }
  515. } // End namespace LLCore