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