kmsp11/util/handle_map.h (60 lines of code) (raw):

/* * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef KMSP11_UTIL_HANDLE_MAP_H_ #define KMSP11_UTIL_HANDLE_MAP_H_ #include "absl/container/flat_hash_map.h" #include "absl/functional/function_ref.h" #include "absl/status/statusor.h" #include "kmsp11/cryptoki.h" #include "kmsp11/util/crypto_utils.h" #include "kmsp11/util/errors.h" namespace cloud_kms::kmsp11 { // A HandleMap contains a set of items with assigned CK_ULONG handles. // It is intended for use with the PKCS #11 Session and Object types, both // of which are identified by a handle. template <typename T> class HandleMap { public: // Create a new map. The provided CK_RV will be used for Get and Remove // operations performed against an unknown handle. HandleMap(CK_RV not_found_rv) : not_found_rv_(not_found_rv) {} // Constructs a new T using the provided arguments, adds it to the map, and // returns its handle. template <typename... Args> inline CK_ULONG Add(Args&&... args) { absl::WriterMutexLock lock(&mutex_); // Generate a new handle by picking a random handle and ensuring that it is // not already in use. Repeat this process until we have a useable handle. CK_ULONG handle; do { handle = RandomHandle(); } while (items_.contains(handle)); items_.try_emplace(handle, std::make_shared<T>(std::forward<Args>(args)...)); return handle; } // Gets the map element with the provided handle, or returns NotFound if there // is no element with the provided handle. inline absl::StatusOr<std::shared_ptr<T>> Get(CK_ULONG handle) const { absl::ReaderMutexLock lock(&mutex_); auto it = items_.find(handle); if (it == items_.end()) { return HandleNotFoundError(handle, not_found_rv_, SOURCE_LOCATION); } return it->second; } // Removes the map element with the provided handle, or returns NotFound if // there is no element with the provided handle. inline absl::Status Remove(CK_ULONG handle) { absl::WriterMutexLock lock(&mutex_); auto it = items_.find(handle); if (it == items_.end()) { return HandleNotFoundError(handle, not_found_rv_, SOURCE_LOCATION); } items_.erase(it); return absl::OkStatus(); } // Removes all map elements that match the provided predicate. inline void RemoveIf(absl::FunctionRef<bool(const T&)> predicate) { absl::WriterMutexLock lock(&mutex_); auto it = items_.begin(); while (it != items_.end()) { if (predicate(*it->second)) { items_.erase(it++); } else { it++; } } } private: CK_RV not_found_rv_; mutable absl::Mutex mutex_; absl::flat_hash_map<CK_ULONG, std::shared_ptr<T>> items_ ABSL_GUARDED_BY(mutex_); }; } // namespace cloud_kms::kmsp11 #endif // KMSP11_UTIL_HANDLE_MAP_H_