1/*
2 * Copyright (c) 2008,2011-2012 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// Templates to support HandleObject-like objects
27//
28#ifndef _H_HANDLETEMPLATES
29#define _H_HANDLETEMPLATES
30
31#include <security_utilities/refcount.h>
32#include <security_utilities/threading.h>
33#include <security_utilities/globalizer.h>
34#include <security_cdsa_utilities/cssmerrors.h>
35#include <vector>
36
37#if __GNUC__ > 2
38#include <ext/hash_map>
39using __gnu_cxx::hash_map;
40#else
41#include <hash_map>
42#endif
43
44namespace Security
45{
46
47//
48// A TypedHandle is a trivial mixin class whose only feature is that
49// it has a *handle* whose type is of the caller's choosing.  Subclasses
50// need to assign such a handle during creation.
51//
52template <class _Handle>
53struct TypedHandle
54{
55public:
56    typedef _Handle Handle;
57
58    static const _Handle invalidHandle = 0;
59
60    _Handle handle() const     { return mMyHandle; }
61    bool validHandle() const  { return mValid; }
62
63protected:
64    TypedHandle(_Handle h);
65    TypedHandle();
66
67    void setHandle(_Handle h)
68    {
69        assert(!mValid);    // guard against redefinition
70        mMyHandle = h;
71        mValid = true;
72    }
73    void clearHandle()
74    {
75        assert(mValid);
76        mValid = false;
77    }
78
79private:
80    _Handle mMyHandle;           // our handle value
81    bool mValid;                // is the handle (still) valid?
82};
83
84//
85// MappingHandle wraps a map indexed by handles of the chosen type.
86// A MappingHandle makes up its own handle based on some mechanism that you
87// know nothing about.
88//
89// Please be very careful about the limits of the object contract here.
90// We promise to invent a suitable, unique handle for each MappingHandle in
91// existence within one address space. We promise that if you hand that
92// handle to the various MappingHandle<>::find() variants, we will give you
93// back the MappingHandle that created it. We promise to throw if you pass
94// a bad handle to those MappingHandle<>::find() variants. This is the
95// entire contract.
96//
97template <class _Handle>
98class MappingHandle : public TypedHandle<_Handle>
99{
100protected:
101    class State;
102
103public:
104    typedef typename TypedHandle<_Handle>::Handle Handle;
105    virtual ~MappingHandle()
106    {
107        State &st = state();
108        StLock<Mutex> _(st);
109        st.erase(this);
110    }
111
112    template <class SubType>
113    static SubType &find(_Handle handle, CSSM_RETURN error);
114
115	template <class Subtype>
116	static Subtype &findAndLock(_Handle handle, CSSM_RETURN error);
117
118	template <class Subtype>
119	static Subtype &findAndKill(_Handle handle, CSSM_RETURN error);
120
121	template <class Subtype>
122	static RefPointer<Subtype> findRef(_Handle handle, CSSM_RETURN error);
123
124	template <class Subtype>
125	static RefPointer<Subtype> findRefAndLock(_Handle handle, CSSM_RETURN error);
126
127	template <class Subtype>
128	static RefPointer<Subtype> findRefAndKill(_Handle handle, CSSM_RETURN error);
129
130    // @@@  Remove when 4003540 is fixed
131    template <class Subtype>
132    static void findAllRefs(std::vector<_Handle> &refs) {
133        state().template findAllRefs<Subtype>(refs);
134    }
135
136protected:
137    virtual void lock();
138    virtual bool tryLock();
139
140    typedef hash_map<_Handle, MappingHandle<_Handle> *> HandleMap;
141
142    MappingHandle();
143
144    class State : public Mutex, public HandleMap
145    {
146    public:
147        State();
148        uint32_t nextSeq()  { return ++sequence; }
149
150        bool handleInUse(_Handle h);
151        MappingHandle<_Handle> *find(_Handle h, CSSM_RETURN error);
152        typename HandleMap::iterator locate(_Handle h, CSSM_RETURN error);
153        void add(_Handle h, MappingHandle<_Handle> *obj);
154        void erase(MappingHandle<_Handle> *obj);
155        void erase(typename HandleMap::iterator &it);
156        // @@@  Remove when 4003540 is fixed
157        template <class SubType> void findAllRefs(std::vector<_Handle> &refs);
158
159    private:
160        uint32_t sequence;
161    };
162
163private:
164    //
165    // Create the handle to be used by the map
166    //
167    void make();
168
169    static ModuleNexus<typename MappingHandle<_Handle>::State> state;
170};
171
172//
173// MappingHandle class methods
174// Type-specific ways to access the map in various ways
175//
176template <class _Handle>
177template <class Subclass>
178inline Subclass &MappingHandle<_Handle>::find(_Handle handle, CSSM_RETURN error)
179{
180    Subclass *sub;
181    if (!(sub = dynamic_cast<Subclass *>(state().find(handle, error))))
182        CssmError::throwMe(error);
183    return *sub;
184}
185
186template <class _Handle>
187template <class Subclass>
188inline Subclass &MappingHandle<_Handle>::findAndLock(_Handle handle,
189                                             CSSM_RETURN error)
190{
191    for (;;) {
192        typename HandleMap::iterator it = state().locate(handle, error);
193        StLock<Mutex> _(state(), true);	// locate() locked it
194        Subclass *sub;
195        if (!(sub = dynamic_cast<Subclass *>(it->second)))
196            CssmError::throwMe(error);	// bad type
197        if (it->second->tryLock())		// try to lock it
198            return *sub;				// okay, go
199        Thread::yield();				// object lock failed, backoff and retry
200    }
201}
202
203template <class _Handle>
204template <class Subclass>
205inline Subclass &MappingHandle<_Handle>::findAndKill(_Handle handle,
206                                             CSSM_RETURN error)
207{
208    for (;;) {
209        typename HandleMap::iterator it = state().locate(handle, error);
210        StLock<Mutex> _(state(), true);	// locate() locked it
211        Subclass *sub;
212        if (!(sub = dynamic_cast<Subclass *>(it->second)))
213            CssmError::throwMe(error);	// bad type
214        if (it->second->tryLock()) {	// try to lock it
215            state().erase(it);			// kill the handle
216            return *sub;				// okay, go
217        }
218        Thread::yield();				// object lock failed, backoff and retry
219    }
220}
221
222template <class _Handle>
223template <class Subclass>
224inline RefPointer<Subclass> MappingHandle<_Handle>::findRef(_Handle handle,
225                                                    CSSM_RETURN error)
226{
227    typename HandleMap::iterator it = state().locate(handle, error);
228    StLock<Mutex> _(state(), true); // locate() locked it
229    Subclass *sub;
230    if (!(sub = dynamic_cast<Subclass *>(it->second)))
231        CssmError::throwMe(error);
232    return sub;
233}
234
235template <class _Handle>
236template <class Subclass>
237inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndLock(_Handle handle,
238                                                           CSSM_RETURN error)
239{
240    for (;;) {
241        typename HandleMap::iterator it = state().locate(handle, error);
242        StLock<Mutex> _(state(), true);	// locate() locked it
243        Subclass *sub;
244        if (!(sub = dynamic_cast<Subclass *>(it->second)))
245            CssmError::throwMe(error);	// bad type
246        if (it->second->tryLock())		// try to lock it
247            return sub;				// okay, go
248        Thread::yield();				// object lock failed, backoff and retry
249    }
250}
251
252template <class _Handle>
253template <class Subclass>
254inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndKill(_Handle handle,
255                                                           CSSM_RETURN error)
256{
257    for (;;) {
258        typename HandleMap::iterator it = state().locate(handle, error);
259        StLock<Mutex> _(state(), true);	// locate() locked it
260        Subclass *sub;
261        if (!(sub = dynamic_cast<Subclass *>(it->second)))
262            CssmError::throwMe(error);	// bad type
263        if (it->second->tryLock()) {	// try to lock it
264            state().erase(it);			// kill the handle
265            return sub;					// okay, go
266        }
267        Thread::yield();				// object lock failed, backoff and retry
268    }
269}
270
271//
272// @@@  Remove when 4003540 is fixed
273//
274// This is a hack to fix 3981388 and should NOT be used elsewhere.
275// Also, do not follow this code's example: State methods should not
276// implement type-specific behavior.
277//
278template <class _Handle>
279template <class Subtype>
280void MappingHandle<_Handle>::State::findAllRefs(std::vector<_Handle> &refs)
281{
282    StLock<Mutex> _(*this);
283    typename HandleMap::iterator it = (*this).begin();
284    for (; it != (*this).end(); ++it)
285    {
286        Subtype *obj = dynamic_cast<Subtype *>(it->second);
287        if (obj)
288            refs.push_back(it->first);
289    }
290}
291
292
293} // end namespace Security
294
295#endif //_H_HANDLETEMPLATES
296