]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/handleobject.h
Security-164.1.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / handleobject.h
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // handleobject - give an object a process-global unique handle
21 //
22 #ifndef _H_HANDLEOBJECT
23 #define _H_HANDLEOBJECT
24
25 #include <Security/cssm.h>
26 #include <Security/utilities.h>
27 #include <Security/threading.h>
28 #include <Security/globalizer.h>
29
30 #if __GNUC__ > 2
31 #include <ext/hash_map>
32 using __gnu_cxx::hash_map;
33 #else
34 #include <hash_map>
35 #endif
36
37 namespace Security
38 {
39
40 //
41 // A HandledObject is a trivial mixin class whose only feature is that
42 // it has a *handle*, in the form of (currently) a CSSM_HANDLE of some kind.
43 // Subclasses need to assign such a handle during creation.
44 //
45 class HandledObject {
46 public:
47 typedef CSSM_HANDLE Handle;
48 static const Handle invalidHandle = 0;
49
50 Handle handle() const { return mMyHandle; }
51 bool validHandle() const { return mValid; }
52
53 protected:
54 HandledObject(Handle h) : mMyHandle(h), mValid(true) { }
55 HandledObject() { /*IFDEBUG(*/ mMyHandle = invalidHandle/*)*/ ; mValid = false; }
56
57 void setHandle(Handle h)
58 {
59 assert(!mValid); // guard against redefinition
60 mMyHandle = h;
61 mValid = true;
62 }
63 void clearHandle()
64 { assert(mValid); mValid = false; }
65
66 private:
67 Handle mMyHandle; // our handle value
68 bool mValid; // is the handle (still) valid?
69 };
70
71
72 //
73 // Mapping CSSM_HANDLE values to object pointers and back.
74 // A HandleObject is a HandledObject (see above) that makes up its own handle
75 // based on some mechanism that you know nothing about.
76 //
77 // Please be very careful about the limits of the object contract here.
78 // We promise to invent a suitable, unique Handle for each HandleObject in
79 // existence within one address space. We promise that if you hand that handle
80 // to the various findHandle<>() variants, we will give you back the HandleObject
81 // that created it. This is the entire contract.
82 // We *will* make some efforts to diagnose invalid handles and throw exceptions on
83 // them, but the find() operation is supposed to be *fast*, so no heroic measures
84 // will be taken.
85 //
86 class HandleObject : public HandledObject {
87 NOCOPY(HandleObject)
88 class State;
89
90 public:
91 HandleObject() { state().make(this); }
92 virtual ~HandleObject();
93
94 public:
95 template <class Subtype>
96 static Subtype &find(CSSM_HANDLE handle, CSSM_RETURN error);
97
98 template <class Subtype>
99 static Subtype &findAndLock(CSSM_HANDLE handle, CSSM_RETURN error);
100
101 template <class Subtype>
102 static Subtype &findAndKill(CSSM_HANDLE handle, CSSM_RETURN error);
103
104 protected:
105 virtual void lock();
106 virtual bool tryLock();
107
108 private:
109 typedef hash_map<CSSM_HANDLE, HandleObject *> HandleMap;
110 class State : public Mutex {
111 public:
112 State();
113 void make(HandleObject *obj);
114 HandleObject *find(Handle h, CSSM_RETURN error);
115 HandleMap::iterator locate(Handle h, CSSM_RETURN error);
116 void erase(HandleObject *obj);
117 void erase(HandleMap::iterator &it);
118
119 private:
120 HandleMap handleMap;
121 uint32 sequence;
122 };
123
124 static ModuleNexus<State> state;
125 };
126
127
128 //
129 // Type-specific ways to access the HandleObject map in various ways
130 //
131 template <class Subclass>
132 inline Subclass &HandleObject::find(CSSM_HANDLE handle, CSSM_RETURN error)
133 {
134 Subclass *sub;
135 if (!(sub = dynamic_cast<Subclass *>(state().find(handle, error))))
136 CssmError::throwMe(error);
137 return *sub;
138 }
139
140 template <class Subclass>
141 inline Subclass &HandleObject::findAndLock(CSSM_HANDLE handle,
142 CSSM_RETURN error)
143 {
144 for (;;) {
145 HandleMap::iterator it = state().locate(handle, error);
146 StLock<Mutex> _(state(), true); // locate() locked it
147 Subclass *sub;
148 if (!(sub = dynamic_cast<Subclass *>(it->second)))
149 CssmError::throwMe(error); // bad type
150 if (it->second->tryLock()) // try to lock it
151 return *sub; // okay, go
152 Thread::yield(); // object lock failed, backoff and retry
153 }
154 }
155
156 template <class Subclass>
157 inline Subclass &HandleObject::findAndKill(CSSM_HANDLE handle,
158 CSSM_RETURN error)
159 {
160 for (;;) {
161 HandleMap::iterator it = state().locate(handle, error);
162 StLock<Mutex> _(state(), true); // locate() locked it
163 Subclass *sub;
164 if (!(sub = dynamic_cast<Subclass *>(it->second)))
165 CssmError::throwMe(error); // bad type
166 if (it->second->tryLock()) { // try to lock it
167 state().erase(it); // kill the handle
168 return *sub; // okay, go
169 }
170 Thread::yield(); // object lock failed, backoff and retry
171 }
172 }
173
174
175 //
176 // Compatibility with old (global function) accessors
177 //
178 template <class Subclass>
179 inline Subclass &findHandle(CSSM_HANDLE handle,
180 CSSM_RETURN error = CSSMERR_CSSM_INVALID_ADDIN_HANDLE)
181 { return HandleObject::find<Subclass>(handle, error); }
182
183 template <class Subclass>
184 inline Subclass &findHandleAndLock(CSSM_HANDLE handle,
185 CSSM_RETURN error = CSSMERR_CSSM_INVALID_ADDIN_HANDLE)
186 { return HandleObject::findAndLock<Subclass>(handle, error); }
187
188 template <class Subclass>
189 inline Subclass &killHandle(CSSM_HANDLE handle,
190 CSSM_RETURN error = CSSMERR_CSSM_INVALID_ADDIN_HANDLE)
191 { return HandleObject::findAndKill<Subclass>(handle, error); }
192
193
194 } // end namespace Security
195
196 #endif //_H_HANDLEOBJECT