]> git.ipfire.org Git - thirdparty/squid.git/blob - src/security/LockingPointer.h
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / security / LockingPointer.h
1 /*
2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 #ifndef SQUID_SRC_SECURITY_LOCKINGPOINTER_H
10 #define SQUID_SRC_SECURITY_LOCKINGPOINTER_H
11
12 #include "base/HardFun.h"
13
14 #if USE_OPENSSL
15 #include "compat/openssl.h"
16 #if HAVE_OPENSSL_CRYPTO_H
17 #include <openssl/crypto.h>
18 #endif
19
20 // Macro to be used to define the C++ wrapper function of a sk_*_pop_free
21 // openssl family functions. The C++ function suffixed with the _free_wrapper
22 // extension
23 #define sk_free_wrapper(sk_object, argument, freefunction) \
24 extern "C++" inline void sk_object ## _free_wrapper(argument a) { \
25 sk_object ## _pop_free(a, freefunction); \
26 }
27
28 #endif /* USE_OPENSSL */
29
30 // Macro to be used to define the C++ equivalent function of an extern "C"
31 // function. The C++ function suffixed with the _cpp extension
32 #define CtoCpp1(function, argument) \
33 extern "C++" inline void function ## _cpp(argument a) { \
34 function(a); \
35 }
36
37 namespace Security
38 {
39
40 inline bool nilFunction(const void *) { return false; }
41 typedef HardFun<bool, const void *, nilFunction> NilFunctor;
42
43 /**
44 * A shared pointer to a reference-counting Object with library-specific
45 * absorption, locking, and unlocking implementations. The API largely
46 * follows std::shared_ptr.
47 *
48 * The constructor and the resetWithoutLocking() method import a raw Object pointer.
49 * Normally, reset() would lock(), but libraries like OpenSSL
50 * pre-lock objects before they are fed to LockingPointer, necessitating
51 * this resetWithoutLocking() customization hook.
52 */
53 template <typename T, void (*UnLocker)(T *t), class Locker = NilFunctor>
54 class LockingPointer
55 {
56 public:
57 /// a helper label to simplify this objects API definitions below
58 typedef Security::LockingPointer<T, UnLocker, Locker> SelfType;
59
60 /**
61 * Construct directly from a raw pointer.
62 * This action requires that the producer of that pointer has already
63 * created one reference lock for the object pointed to.
64 * Our destructor will do the matching unlock.
65 */
66 explicit LockingPointer(T *t = nullptr): raw(nullptr) {
67 // de-optimized for clarity about non-locking
68 resetWithoutLocking(t);
69 }
70
71 /// use the custom UnLocker to unlock any value still stored.
72 ~LockingPointer() { unlock(); }
73
74 // copy semantics are okay only when adding a lock reference
75 LockingPointer(const SelfType &o) : raw(nullptr) {
76 resetAndLock(o.get());
77 }
78 const SelfType &operator =(const SelfType &o) {
79 resetAndLock(o.get());
80 return *this;
81 }
82
83 LockingPointer(SelfType &&o) : raw(nullptr) {
84 resetWithoutLocking(o.release());
85 }
86 SelfType &operator =(SelfType &&o) {
87 if (o.get() != raw)
88 resetWithoutLocking(o.release());
89 return *this;
90 }
91
92 bool operator !() const { return !raw; }
93 explicit operator bool() const { return raw; }
94 bool operator ==(const SelfType &o) const { return (o.get() == raw); }
95 bool operator !=(const SelfType &o) const { return (o.get() != raw); }
96
97 T *operator ->() const { return raw; }
98
99 /// Returns raw and possibly nullptr pointer
100 T *get() const { return raw; }
101
102 /// Reset raw pointer - unlock any previous one and save new one without locking.
103 void resetWithoutLocking(T *t) {
104 unlock();
105 raw = t;
106 }
107
108 void resetAndLock(T *t) {
109 if (t != get()) {
110 resetWithoutLocking(t);
111 lock(t);
112 }
113 }
114
115 /// Forget the raw pointer - unlock if any value was set. Become a nil pointer.
116 void reset() { unlock(); }
117
118 /// Forget the raw pointer without unlocking it. Become a nil pointer.
119 T *release() {
120 T *ret = raw;
121 raw = nullptr;
122 return ret;
123 }
124
125 private:
126 /// The lock() method increments Object's reference counter.
127 void lock(T *t) {
128 if (t) {
129 Locker doLock;
130 doLock(t);
131 }
132 }
133
134 /// Become a nil pointer. Decrements any pointed-to Object's reference counter
135 /// using UnLocker which ideally destroys the object when the counter reaches zero.
136 void unlock() {
137 if (raw) {
138 UnLocker(raw);
139 raw = nullptr;
140 }
141 }
142
143 /**
144 * Normally, no other code will have this raw pointer.
145 *
146 * However, OpenSSL does some strange and not always consistent things.
147 * OpenSSL library may keep its own internal raw pointers and manage
148 * their reference counts independently, or it may not. This varies between
149 * API functions, though it is usually documented.
150 *
151 * This means the caller code needs to be carefuly written to use the correct
152 * reset method and avoid the raw-pointer constructor unless OpenSSL function
153 * producing the pointer is clearly documented as incrementing a lock for it.
154 */
155 T *raw;
156 };
157
158 } // namespace Security
159
160 #endif /* SQUID_SRC_SECURITY_LOCKINGPOINTER_H */
161