1d2c658b95b90ea758eafcbcc261f115b5ad5fee
[platform/core/security/cynara.git] / src / client / cache / CapacityCache.cpp
1 /*
2  *  Copyright (c) 2014 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        CapacityCache.cpp
18  * @author      Zofia Abramowska <z.abramowska@samsung.com>
19  * @version     1.0
20  * @brief       This file contains capacity cache implementation.
21  */
22
23 #include <cinttypes>
24
25 #include <cynara-client-error.h>
26 #include <log/log.h>
27
28 #include <cache/CapacityCache.h>
29
30 namespace Cynara {
31
32 int CapacityCache::get(const ClientSession &session, const PolicyKey &key) {
33     //This can be very time heavy. This part is welcomed to be optimized.
34     if (session != m_session) {
35         LOGD("Session changed from %s to %s.", m_session.c_str(), session.c_str());
36         clear();
37         m_session = session;
38         return CYNARA_API_CACHE_MISS;
39     }
40     auto resultIt = m_keyValue.find(keyToString(key));
41     //Do we have entry in cache?
42     if (resultIt == m_keyValue.end()) {
43         LOGD("No entry for client=%s user=%s privilege=%s.",
44                 key.client().toString().c_str(),
45                 key.user().toString().c_str(),
46                 key.privilege().toString().c_str());
47         return CYNARA_API_CACHE_MISS;
48     } else {
49         LOGD("Entry available for client=%s user=%s privilege=%s",
50                 key.client().toString().c_str(),
51                 key.user().toString().c_str(),
52                 key.privilege().toString().c_str());
53
54         auto pluginIt = m_plugins.find(resultIt->second.first.policyType());
55         if (pluginIt == m_plugins.end()) {
56             LOGE("No plugin registered for given PolicyType : %" PRIu16,
57                     resultIt->second.first.policyType());
58             return CYNARA_API_ACCESS_DENIED;
59         }
60
61         //Is it still usable?
62         InterpreterInterfacePtr plugin = pluginIt->second;
63         if (plugin->isUsable(resultIt->second.first)) {
64             LOGD("Entry usable.");
65             m_keyUsage.splice(m_keyUsage.begin(), m_keyUsage, resultIt->second.second);
66             return plugin->toResult(resultIt->second.first);
67         }
68         //Remove unusable entry
69         LOGD("Entry not usable");
70         auto usageIt = resultIt->second.second;
71         m_keyUsage.erase(usageIt);
72         m_keyValue.erase(resultIt);
73         return CYNARA_API_CACHE_MISS;
74     }
75 }
76
77 void CapacityCache::clear(void) {
78     m_keyUsage.clear();
79     m_keyValue.clear();
80     m_session.clear();
81 }
82
83 std::string CapacityCache::keyToString(const PolicyKey &key) {
84     const char separator = '\1';
85     auto clientStr = key.client().toString();
86     auto privilegeStr = key.privilege().toString();
87     auto userStr = key.user().toString();
88     return clientStr + privilegeStr + userStr + separator +
89             std::to_string(clientStr.size()) + separator +
90             std::to_string(privilegeStr.size()) + separator +
91             std::to_string(userStr.size());
92 }
93
94 void CapacityCache::evict(void) {
95
96     auto lastUsedKey = m_keyUsage.back();
97     m_keyUsage.pop_back();
98
99     auto value_it = m_keyValue.find(lastUsedKey);
100     m_keyValue.erase(value_it);
101 }
102
103 int CapacityCache::update(const ClientSession &session,
104                           const PolicyKey &key,
105                           const PolicyResult &result) {
106     //This can be very time heavy. This part is welcomed to be optimized.
107     if (session != m_session) {
108         LOGD("Session changed from %s to %s.", m_session.c_str(), session.c_str());
109         clear();
110         m_session = session;
111     }
112
113     auto pluginIt = m_plugins.find(result.policyType());
114
115     //No registered plugin for returned type of policy
116     if (pluginIt == m_plugins.end()) {
117         LOGE("No registered plugin for given PolicyType: %" PRIu16,
118                 result.policyType());
119         return CYNARA_API_ACCESS_DENIED;
120     }
121     auto plugin = pluginIt->second;
122
123     if (m_capacity != 0) {
124         if (plugin->isCacheable(result)) {
125             LOGD("Entry cacheable");
126             if (m_keyValue.size() == m_capacity) {
127                 LOGD("Capacity reached.");
128                 evict();
129             }
130             m_keyUsage.push_front(keyToString(key));
131             m_keyValue[keyToString(key)] = std::make_pair(result, m_keyUsage.begin());
132         }
133     }
134     return plugin->toResult(result);
135 }
136
137 } // namespace Cynara