PageRenderTime 39ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/src/client-async/logic/Logic.cpp

https://gitlab.com/admin-github-cloud/cynara
C++ | 457 lines | 351 code | 75 blank | 31 comment | 58 complexity | d631c8edf5619a147127fd8c115de7d4 MD5 | raw file
  1. /*
  2. * Copyright (c) 2014-2016 Samsung Electronics Co., Ltd All Rights Reserved
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License
  15. */
  16. /**
  17. * @file src/client-async/logic/Logic.cpp
  18. * @author Marcin Niesluchowski <m.niesluchow@samsung.com>
  19. * @author Zofia Abramowska <z.abramowska@samsung.com>
  20. * @author Aleksander Zdyb <a.zdyb@samsung.com>
  21. * @version 1.0
  22. * @brief This file contains implementation of Logic class - main
  23. * libcynara-client-async class
  24. */
  25. #include <cinttypes>
  26. #include <memory>
  27. #include <cache/CapacityCache.h>
  28. #include <common.h>
  29. #include <config/PathConfig.h>
  30. #include <exceptions/Exception.h>
  31. #include <exceptions/NoMemoryException.h>
  32. #include <exceptions/UnexpectedErrorException.h>
  33. #include <log/log.h>
  34. #include <plugins/NaiveInterpreter.h>
  35. #include <protocol/ProtocolClient.h>
  36. #include <request/CancelRequest.h>
  37. #include <request/CheckRequest.h>
  38. #include <request/MonitorEntriesPutRequest.h>
  39. #include <request/MonitorEntryPutRequest.h>
  40. #include <request/SimpleCheckRequest.h>
  41. #include <response/CancelResponse.h>
  42. #include <response/CheckResponse.h>
  43. #include <response/SimpleCheckResponse.h>
  44. #include <sockets/Socket.h>
  45. #include "Logic.h"
  46. namespace Cynara {
  47. static ProtocolFrameSequenceNumber generateSequenceNumber(void) {
  48. static ProtocolFrameSequenceNumber sequenceNumber = 0;
  49. return ++sequenceNumber;
  50. }
  51. Logic::Logic(cynara_status_callback callback, void *userStatusData, const Configuration &conf)
  52. : m_statusCallback(callback, userStatusData), m_cache(conf.getCacheSize()),
  53. m_socketClient(PathConfig::SocketPath::client, std::make_shared<ProtocolClient>()),
  54. m_operationPermitted(true), m_inAnswerCancelResponseCallback(false),
  55. m_monitoringEnabled(conf.monitoringEnabled()) {
  56. auto naiveInterpreter = std::make_shared<NaiveInterpreter>();
  57. for (auto &descr : naiveInterpreter->getSupportedPolicyDescr()) {
  58. m_cache.registerPlugin(descr, naiveInterpreter);
  59. }
  60. }
  61. Logic::~Logic() {
  62. m_operationPermitted = false;
  63. if (m_monitoringEnabled) {
  64. // The client invoked cynara_async_finish(), so it's basically game over.
  65. // Just try to flush as many entries as possible, before the socket is replete.
  66. for (const auto &entry : m_monitorCache.entries()) {
  67. ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber();
  68. MonitorEntryPutRequest request(entry, sequenceNumber);
  69. m_socketClient.appendRequest(request);
  70. }
  71. if (m_socketClient.sendToCynara() != Socket::SendStatus::ALL_DATA_SENT) {
  72. LOGW("Some monitor entries were lost");
  73. }
  74. }
  75. for (auto &kv : m_checks) {
  76. if (!kv.second.cancelled())
  77. kv.second.callback().onFinish(kv.first);
  78. }
  79. m_statusCallback.onDisconnected();
  80. }
  81. int Logic::checkCache(const std::string &client, const std::string &session,
  82. const std::string &user, const std::string &privilege) {
  83. if (!m_operationPermitted)
  84. return CYNARA_API_OPERATION_NOT_ALLOWED;
  85. if (!checkCacheValid())
  86. return CYNARA_API_CACHE_MISS;
  87. auto ret = m_cache.get(session, PolicyKey(client, user, privilege));
  88. if (m_monitoringEnabled) {
  89. // Cache returns only CYNARA_API_ACCESS_ALLOWED, CYNARA_API_ACCESS_DENIED
  90. // and CYNARA_API_CACHE_MISS. The condition below must be revamped,
  91. // if this invariant changes.
  92. if (ret != CYNARA_API_CACHE_MISS) {
  93. updateMonitor({client, user, privilege}, ret);
  94. }
  95. if (m_monitorCache.shouldFlush()) {
  96. flushMonitor();
  97. }
  98. }
  99. return ret;
  100. }
  101. int Logic::createCheckRequest(const std::string &client, const std::string &session,
  102. const std::string &user, const std::string &privilege,
  103. cynara_check_id &checkId, cynara_response_callback callback,
  104. void *userResponseData) {
  105. return createRequest(false, client, session, user, privilege, checkId, callback,
  106. userResponseData);
  107. }
  108. int Logic::createSimpleRequest(const std::string &client, const std::string &session,
  109. const std::string &user, const std::string &privilege,
  110. cynara_check_id &checkId, cynara_response_callback callback,
  111. void *userResponseData) {
  112. return createRequest(true, client, session, user, privilege, checkId, callback,
  113. userResponseData);
  114. }
  115. int Logic::createRequest(bool simple, const std::string &client, const std::string &session,
  116. const std::string &user, const std::string &privilege,
  117. cynara_check_id &checkId, cynara_response_callback callback,
  118. void *userResponseData) {
  119. if (!m_operationPermitted)
  120. return CYNARA_API_OPERATION_NOT_ALLOWED;
  121. if (!ensureConnection())
  122. return CYNARA_API_SERVICE_NOT_AVAILABLE;
  123. ProtocolFrameSequenceNumber sequenceNumber;
  124. if (!m_sequenceContainer.get(sequenceNumber))
  125. return CYNARA_API_MAX_PENDING_REQUESTS;
  126. PolicyKey key(client, user, privilege);
  127. ResponseCallback responseCallback(callback, userResponseData);
  128. m_checks.insert(CheckPair(sequenceNumber, CheckData(key, session, responseCallback,
  129. simple)));
  130. if (simple)
  131. m_socketClient.appendRequest(SimpleCheckRequest(key, sequenceNumber));
  132. else
  133. m_socketClient.appendRequest(CheckRequest(key, sequenceNumber));
  134. onStatusChange(m_socketClient.getSockFd(), cynara_async_status::CYNARA_STATUS_FOR_RW);
  135. checkId = static_cast<cynara_check_id>(sequenceNumber);
  136. return CYNARA_API_SUCCESS;
  137. }
  138. int Logic::process(void) {
  139. if (!m_operationPermitted)
  140. return CYNARA_API_OPERATION_NOT_ALLOWED;
  141. bool completed;
  142. while (true) {
  143. int ret = completeConnection(completed);
  144. if (!completed)
  145. return ret;
  146. if (processOut() && processIn())
  147. return CYNARA_API_SUCCESS;
  148. onDisconnected();
  149. if (!connect())
  150. return CYNARA_API_SERVICE_NOT_AVAILABLE;
  151. }
  152. }
  153. int Logic::cancelRequest(cynara_check_id checkId) {
  154. if (!m_operationPermitted)
  155. return CYNARA_API_OPERATION_NOT_ALLOWED;
  156. if (!ensureConnection())
  157. return CYNARA_API_SERVICE_NOT_AVAILABLE;
  158. auto it = m_checks.find(checkId);
  159. if (it == m_checks.end() || it->second.cancelled())
  160. return CYNARA_API_INVALID_PARAM;
  161. m_socketClient.appendRequest(CancelRequest(it->first));
  162. it->second.cancel();
  163. bool onAnswerCancel = m_inAnswerCancelResponseCallback;
  164. m_inAnswerCancelResponseCallback = true;
  165. it->second.callback().onCancel(it->first);
  166. m_inAnswerCancelResponseCallback = onAnswerCancel;
  167. onStatusChange(m_socketClient.getSockFd(), cynara_async_status::CYNARA_STATUS_FOR_RW);
  168. return CYNARA_API_SUCCESS;
  169. }
  170. bool Logic::isFinishPermitted(void) {
  171. return m_operationPermitted && !m_inAnswerCancelResponseCallback;
  172. }
  173. bool Logic::checkCacheValid(void) {
  174. return m_socketClient.isConnected();
  175. }
  176. void Logic::prepareRequestsToSend(void) {
  177. for (auto it = m_checks.begin(); it != m_checks.end();) {
  178. if (it->second.cancelled()) {
  179. m_sequenceContainer.release(it->first);
  180. it = m_checks.erase(it);
  181. } else {
  182. if (it->second.isSimple())
  183. m_socketClient.appendRequest(SimpleCheckRequest(it->second.key(), it->first));
  184. else
  185. m_socketClient.appendRequest(CheckRequest(it->second.key(), it->first));
  186. ++it;
  187. }
  188. }
  189. }
  190. bool Logic::processOut(void) {
  191. switch (m_socketClient.sendToCynara()) {
  192. case Socket::SendStatus::ALL_DATA_SENT:
  193. onStatusChange(m_socketClient.getSockFd(),
  194. cynara_async_status::CYNARA_STATUS_FOR_READ);
  195. case Socket::SendStatus::PARTIAL_DATA_SENT:
  196. return true;
  197. default:
  198. return false;
  199. }
  200. }
  201. Logic::CheckMap::iterator Logic::checkResponseValid(const Response &response) {
  202. auto it = m_checks.find(response.sequenceNumber());
  203. if (it == m_checks.end()) {
  204. LOGC("Critical error. Unknown checkResponse received: sequenceNumber = [%" PRIu16 "]",
  205. response.sequenceNumber());
  206. throw UnexpectedErrorException("Unexpected response from cynara service");
  207. }
  208. return it;
  209. }
  210. void Logic::releaseRequest(Logic::CheckMap::iterator reqIt) {
  211. m_sequenceContainer.release(reqIt->first);
  212. m_checks.erase(reqIt);
  213. }
  214. void Logic::processCheckResponse(const CheckResponse &checkResponse) {
  215. LOGD("checkResponse: policyType = [%" PRIu16 "], metadata = <%s>",
  216. checkResponse.m_resultRef.policyType(),
  217. checkResponse.m_resultRef.metadata().c_str());
  218. auto it = checkResponseValid(checkResponse);
  219. int result = m_cache.update(it->second.session(), it->second.key(),
  220. checkResponse.m_resultRef);
  221. CheckData checkData(std::move(it->second));
  222. releaseRequest(it);
  223. // Please mind that updating monitor here makes only successful checks count.
  224. // This is an arbitrary decision.
  225. updateMonitor(checkData.key(), result);
  226. if (!checkData.cancelled()) {
  227. bool onAnswerCancel = m_inAnswerCancelResponseCallback;
  228. m_inAnswerCancelResponseCallback = true;
  229. checkData.callback().onAnswer(
  230. static_cast<cynara_check_id>(checkResponse.sequenceNumber()), result);
  231. m_inAnswerCancelResponseCallback = onAnswerCancel;
  232. }
  233. }
  234. void Logic::processSimpleCheckResponse(const SimpleCheckResponse &response) {
  235. LOGD("simpleCheckResponse");
  236. LOGD("checkResponse: policyType = [%" PRIu16 "], metadata = <%s>",
  237. response.getResult().policyType(),
  238. response.getResult().metadata().c_str());
  239. auto it = checkResponseValid(response);
  240. int result = response.getReturnValue();
  241. if (result == CYNARA_API_SUCCESS)
  242. result = m_cache.update(it->second.session(), it->second.key(),
  243. response.getResult());
  244. CheckData checkData(std::move(it->second));
  245. releaseRequest(it);
  246. if (!checkData.cancelled()) {
  247. bool onAnswerCancel = m_inAnswerCancelResponseCallback;
  248. m_inAnswerCancelResponseCallback = true;
  249. checkData.callback().onAnswer(
  250. static_cast<cynara_check_id>(response.sequenceNumber()), result);
  251. m_inAnswerCancelResponseCallback = onAnswerCancel;
  252. }
  253. }
  254. void Logic::processCancelResponse(const CancelResponse &cancelResponse) {
  255. auto it = checkResponseValid(cancelResponse);
  256. if (!it->second.cancelled()) {
  257. LOGC("Critical error. CancelRequest not sent: sequenceNumber = [%" PRIu16 "]",
  258. cancelResponse.sequenceNumber());
  259. throw UnexpectedErrorException("Unexpected response from cynara service");
  260. }
  261. releaseRequest(it);
  262. }
  263. void Logic::processResponses(void) {
  264. ResponsePtr response;
  265. CheckResponsePtr checkResponse;
  266. CancelResponsePtr cancelResponse;
  267. SimpleCheckResponsePtr simpleResponse;
  268. while ((response = m_socketClient.getResponse())) {
  269. checkResponse = std::dynamic_pointer_cast<CheckResponse>(response);
  270. if (checkResponse) {
  271. processCheckResponse(*checkResponse);
  272. continue;
  273. }
  274. cancelResponse = std::dynamic_pointer_cast<CancelResponse>(response);
  275. if (cancelResponse) {
  276. processCancelResponse(*cancelResponse);
  277. continue;
  278. }
  279. simpleResponse = std::dynamic_pointer_cast<SimpleCheckResponse>(response);
  280. if (simpleResponse) {
  281. processSimpleCheckResponse(*simpleResponse);
  282. continue;
  283. }
  284. LOGC("Critical error. Casting Response to known response failed.");
  285. throw UnexpectedErrorException("Unexpected response from cynara service");
  286. }
  287. }
  288. bool Logic::processIn(void) {
  289. if (!m_socketClient.receiveFromCynara())
  290. return false;
  291. processResponses();
  292. return true;
  293. }
  294. cynara_async_status Logic::socketDataStatus(void) {
  295. return m_socketClient.isDataToSend() ? cynara_async_status::CYNARA_STATUS_FOR_RW
  296. : cynara_async_status::CYNARA_STATUS_FOR_READ;
  297. }
  298. bool Logic::ensureConnection(void) {
  299. if (m_socketClient.isConnected())
  300. return true;
  301. onDisconnected();
  302. return connect();
  303. }
  304. bool Logic::connect(void) {
  305. switch (m_socketClient.connect()) {
  306. case Socket::ConnectionStatus::CONNECTION_SUCCEEDED:
  307. prepareRequestsToSend();
  308. onStatusChange(m_socketClient.getSockFd(), socketDataStatus());
  309. return true;
  310. case Socket::ConnectionStatus::CONNECTION_IN_PROGRESS:
  311. prepareRequestsToSend();
  312. onStatusChange(m_socketClient.getSockFd(), cynara_async_status::CYNARA_STATUS_FOR_RW);
  313. return true;
  314. default:
  315. onServiceNotAvailable();
  316. return false;
  317. }
  318. }
  319. int Logic::completeConnection(bool &completed) {
  320. switch (m_socketClient.completeConnection()) {
  321. case Socket::ConnectionStatus::ALREADY_CONNECTED:
  322. completed = true;
  323. return CYNARA_API_SUCCESS;
  324. case Socket::ConnectionStatus::CONNECTION_SUCCEEDED:
  325. onStatusChange(m_socketClient.getSockFd(), socketDataStatus());
  326. completed = true;
  327. return CYNARA_API_SUCCESS;
  328. case Socket::ConnectionStatus::CONNECTION_IN_PROGRESS:
  329. completed = false;
  330. return CYNARA_API_SUCCESS;
  331. default:
  332. completed = false;
  333. onDisconnected();
  334. onServiceNotAvailable();
  335. return CYNARA_API_SERVICE_NOT_AVAILABLE;
  336. }
  337. }
  338. void Logic::onStatusChange(int sock, cynara_async_status status) {
  339. m_operationPermitted = false;
  340. m_statusCallback.onStatusChange(sock, status);
  341. m_operationPermitted = true;
  342. }
  343. void Logic::onServiceNotAvailable(void)
  344. {
  345. m_operationPermitted = false;
  346. for (auto &kv : m_checks) {
  347. if (!kv.second.cancelled())
  348. kv.second.callback().onDisconnected(kv.first);
  349. }
  350. m_checks.clear();
  351. m_sequenceContainer.clear();
  352. m_operationPermitted = true;
  353. }
  354. void Logic::onDisconnected(void) {
  355. m_operationPermitted = false;
  356. m_cache.clear();
  357. m_statusCallback.onDisconnected();
  358. m_operationPermitted = true;
  359. }
  360. void Logic::updateMonitor(const PolicyKey &policyKey, int result) {
  361. if (!m_monitoringEnabled)
  362. return;
  363. m_monitorCache.update(policyKey, result);
  364. if (m_monitorCache.shouldFlush())
  365. flushMonitor();
  366. }
  367. void Logic::flushMonitor() {
  368. if (!m_monitoringEnabled)
  369. return;
  370. if (m_monitorCache.entries().size() == 0)
  371. return;
  372. if (!ensureConnection()) {
  373. LOGE("Could not flush monitor entries: connection lost");
  374. return;
  375. }
  376. ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber();
  377. MonitorEntriesPutRequest request(m_monitorCache.entries(), sequenceNumber);
  378. m_socketClient.appendRequest(request);
  379. onStatusChange(m_socketClient.getSockFd(), cynara_async_status::CYNARA_STATUS_FOR_RW);
  380. m_monitorCache.clear();
  381. }
  382. } // namespace Cynara