]> git.ipfire.org Git - thirdparty/squid.git/blob - src/security/LockingPointer.h
Merged from trunk rev.14734
[thirdparty/squid.git] / src / security / LockingPointer.h
1 /*
2 * Copyright (C) 1996-2016 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 #if USE_OPENSSL
13 #if HAVE_OPENSSL_CRYPTO_H
14 #include <openssl/crypto.h>
15 #endif
16
17 // Macro to be used to define the C++ wrapper function of a sk_*_pop_free
18 // openssl family functions. The C++ function suffixed with the _free_wrapper
19 // extension
20 #define sk_free_wrapper(sk_object, argument, freefunction) \
21 extern "C++" inline void sk_object ## _free_wrapper(argument a) { \
22 sk_object ## _pop_free(a, freefunction); \
23 }
24
25 #endif /* USE_OPENSSL */
26
27 // Macro to be used to define the C++ equivalent function of an extern "C"
28 // function. The C++ function suffixed with the _cpp extension
29 #define CtoCpp1(function, argument) \
30 extern "C++" inline void function ## _cpp(argument a) { \
31 function(a); \
32 }
33
34 namespace Security
35 {
36
37 /**
38 * A shared pointer to a reference-counting Object with library-specific
39 * absorption, locking, and unlocking implementations. The API largely
40 * follows std::shared_ptr.
41 *
42 * The constructor and the resetWithoutLocking() method import a raw Object pointer.
43 * Normally, reset() would lock(), but libraries like OpenSSL
44 * pre-lock objects before they are fed to LockingPointer, necessitating
45 * this resetWithoutLocking() customization hook.
46 *
47 * The lock() method increments Object's reference counter.
48 *
49 * The unlock() method decrements Object's reference counter and destroys
50 * the object when the counter reaches zero.
51 */
52 template <typename T, void (*UnLocker)(T *t), int lockId>
53 class LockingPointer
54 {
55 public:
56 /// a helper label to simplify this objects API definitions below
57 typedef LockingPointer<T, UnLocker, lockId> 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(t) {}
66
67 /// use the custom UnLocker to unlock any value still stored.
68 ~LockingPointer() { unlock(); }
69
70 // copy semantics are okay only when adding a lock reference
71 explicit LockingPointer(const SelfType &o) : raw(nullptr) { resetAndLock(o.get()); }
72 SelfType &operator =(const SelfType & o) {
73 resetAndLock(o.get());
74 return *this;
75 }
76
77 // move semantics are definitely okay, when possible
78 explicit LockingPointer(SelfType &&) = default;
79 SelfType &operator =(SelfType &&o) {
80 if (o.get() != raw)
81 resetWithoutLocking(o.release());
82 return *this;
83 }
84
85 bool operator !() const { return !raw; }
86 explicit operator bool() const { return raw; }
87
88 /// Returns raw and possibly nullptr pointer
89 T *get() const { return raw; }
90
91 /// Reset raw pointer - unlock any previous one and save new one without locking.
92 void resetWithoutLocking(T *t) {
93 unlock();
94 raw = t;
95 }
96
97 void resetAndLock(T *t) {
98 if (t != get()) {
99 resetWithoutLocking(t);
100 lock(t);
101 }
102 }
103
104 /// Forget the raw pointer without unlocking it. Become a nil pointer.
105 T *release() {
106 T *ret = raw;
107 raw = nullptr;
108 return ret;
109 }
110
111 private:
112 void lock(T *t) {
113 #if USE_OPENSSL
114 if (t)
115 CRYPTO_add(&t->references, 1, lockId);
116 #elif USE_GNUTLS
117 // XXX: GnuTLS does not provide locking ?
118 #else
119 assert(false);
120 #endif
121 }
122
123 /// Unlock the raw pointer. Become a nil pointer.
124 void unlock() {
125 if (raw)
126 UnLocker(raw);
127 raw = nullptr;
128 }
129
130 T *raw; ///< pointer to T object or nullptr
131 };
132
133 } // namespace Security
134
135 #endif /* SQUID_SRC_SECURITY_LOCKINGPOINTER_H */
136