#ifndef _H_HANDLEOBJECT
#define _H_HANDLEOBJECT
#include <Security/cssm.h>
#include <Security/utilities.h>
#include <Security/threading.h>
#include <Security/globalizer.h>
#if __GNUC__ > 2
#include <ext/hash_map>
using __gnu_cxx::hash_map;
#else
#include <hash_map>
#endif
namespace Security
{
class HandledObject {
public:
typedef CSSM_HANDLE Handle;
static const Handle invalidHandle = 0;
Handle handle() const { return mMyHandle; }
bool validHandle() const { return mValid; }
protected:
HandledObject(Handle h) : mMyHandle(h), mValid(true) { }
HandledObject() { mMyHandle = invalidHandle ; mValid = false; }
void setHandle(Handle h)
{
assert(!mValid); mMyHandle = h;
mValid = true;
}
void clearHandle()
{ assert(mValid); mValid = false; }
private:
Handle mMyHandle; bool mValid; };
class HandleObject : public HandledObject {
NOCOPY(HandleObject)
class State;
public:
HandleObject() { state().make(this); }
virtual ~HandleObject();
public:
template <class Subtype>
static Subtype &find(CSSM_HANDLE handle, CSSM_RETURN error);
template <class Subtype>
static Subtype &findAndLock(CSSM_HANDLE handle, CSSM_RETURN error);
template <class Subtype>
static Subtype &findAndKill(CSSM_HANDLE handle, CSSM_RETURN error);
protected:
virtual void lock();
virtual bool tryLock();
private:
typedef hash_map<CSSM_HANDLE, HandleObject *> HandleMap;
class State : public Mutex {
public:
State();
void make(HandleObject *obj);
HandleObject *find(Handle h, CSSM_RETURN error);
HandleMap::iterator locate(Handle h, CSSM_RETURN error);
void erase(HandleObject *obj);
void erase(HandleMap::iterator &it);
private:
HandleMap handleMap;
uint32 sequence;
};
static ModuleNexus<State> state;
};
template <class Subclass>
inline Subclass &HandleObject::find(CSSM_HANDLE handle, CSSM_RETURN error)
{
Subclass *sub;
if (!(sub = dynamic_cast<Subclass *>(state().find(handle, error))))
CssmError::throwMe(error);
return *sub;
}
template <class Subclass>
inline Subclass &HandleObject::findAndLock(CSSM_HANDLE handle,
CSSM_RETURN error)
{
for (;;) {
HandleMap::iterator it = state().locate(handle, error);
StLock<Mutex> _(state(), true); Subclass *sub;
if (!(sub = dynamic_cast<Subclass *>(it->second)))
CssmError::throwMe(error); if (it->second->tryLock()) return *sub; Thread::yield(); }
}
template <class Subclass>
inline Subclass &HandleObject::findAndKill(CSSM_HANDLE handle,
CSSM_RETURN error)
{
for (;;) {
HandleMap::iterator it = state().locate(handle, error);
StLock<Mutex> _(state(), true); Subclass *sub;
if (!(sub = dynamic_cast<Subclass *>(it->second)))
CssmError::throwMe(error); if (it->second->tryLock()) { state().erase(it); return *sub; }
Thread::yield(); }
}
template <class Subclass>
inline Subclass &findHandle(CSSM_HANDLE handle,
CSSM_RETURN error = CSSMERR_CSSM_INVALID_ADDIN_HANDLE)
{ return HandleObject::find<Subclass>(handle, error); }
template <class Subclass>
inline Subclass &findHandleAndLock(CSSM_HANDLE handle,
CSSM_RETURN error = CSSMERR_CSSM_INVALID_ADDIN_HANDLE)
{ return HandleObject::findAndLock<Subclass>(handle, error); }
template <class Subclass>
inline Subclass &killHandle(CSSM_HANDLE handle,
CSSM_RETURN error = CSSMERR_CSSM_INVALID_ADDIN_HANDLE)
{ return HandleObject::findAndKill<Subclass>(handle, error); }
}
#endif //_H_HANDLEOBJECT