dvander@372: /** dvander@375: * vim: set ts=4 : dvander@372: * =============================================================== dvander@376: * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. dvander@376: * All rights reserved. dvander@372: * =============================================================== dvander@372: * dvander@379: * This file is part of the SourceMod/SourcePawn SDK. This file may only be dvander@379: * used or modified under the Terms and Conditions of its License Agreement, dvander@379: * which is found in public/licenses/LICENSE.txt. As of this notice, derivative dvander@379: * works must be licensed under the GNU General Public License (version 2 or dvander@379: * greater). A copy of the GPL is included under public/licenses/GPL.txt. dvander@379: * dvander@379: * To view the latest information, see: http://www.sourcemod.net/license.php dvander@372: * dvander@372: * Version: $Id$ dvander@372: */ dvander@372: dvander@324: #ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_ dvander@324: #define _INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_ dvander@324: dvander@372: /** dvander@372: * @file IHandleSys.h dvander@372: * @brief Defines the interface for creating, reading, and removing Handles. dvander@372: * dvander@372: * The Handle system abstracts generic pointers into typed objects represented by dvander@372: * 32bit codes. This is extremely useful for verifying data integrity and cross-platform dvander@372: * support in SourcePawn scripts. When a Plugin unloads, all its Handles are freed, ensuring dvander@372: * that no memory leaks are present, They have reference counts and thus can be duplicated, dvander@372: * or cloned, and are safe to pass between Plugins even if one is unloaded. dvander@372: * dvander@372: * Handles are created with a given type (custom types may be created). They can have dvander@372: * per-Identity permissions for deletion, reading, and cloning. They also support generic dvander@372: * operations. For example, deleting a Handle will call that type's destructor on the generic dvander@372: * pointer, making cleanup easier for users and eliminating memory leaks. dvander@372: */ dvander@372: dvander@324: #include dvander@324: #include dvander@324: dvander@324: #define SMINTERFACE_HANDLESYSTEM_NAME "IHandleSys" dvander@528: #define SMINTERFACE_HANDLESYSTEM_VERSION 2 dvander@324: dvander@372: /** Specifies no Identity */ dvander@324: #define DEFAULT_IDENTITY NULL dvander@372: /** Specifies no Type. This is invalid for everything but reading a Handle. */ dvander@372: #define NO_HANDLE_TYPE 0 dvander@372: /** Specifies an invalid/NULL Handle */ dvander@372: #define BAD_HANDLE 0 dvander@324: dvander@324: namespace SourceMod dvander@324: { dvander@324: /** dvander@372: * @brief Represents a Handle Type ID. dvander@324: */ dvander@324: typedef unsigned int HandleType_t; dvander@372: dvander@372: /** dvander@372: * @brief Represents a Handle ID. dvander@372: */ dvander@324: typedef unsigned int Handle_t; dvander@324: dvander@324: dvander@372: /* dvander@324: * About type checking: dvander@324: * Types can be inherited - a Parent type ("Supertype") can have child types. dvander@324: * When accessing handles, type checking is done. This table shows how this is resolved: dvander@324: * dvander@324: * HANDLE CHECK -> RESULT dvander@324: * ------ ----- ------ dvander@324: * Parent Parent Success dvander@324: * Parent Child Fail dvander@324: * Child Parent Success dvander@324: * Child Child Success dvander@324: */ dvander@324: dvander@372: /** dvander@372: * @brief Lists the possible handle error codes. dvander@372: */ dvander@324: enum HandleError dvander@324: { dvander@372: HandleError_None = 0, /**< No error */ dvander@372: HandleError_Changed, /**< The handle has been freed and reassigned */ dvander@372: HandleError_Type, /**< The handle has a different type registered */ dvander@372: HandleError_Freed, /**< The handle has been freed */ dvander@372: HandleError_Index, /**< generic internal indexing error */ dvander@372: HandleError_Access, /**< No access permitted to free this handle */ dvander@372: HandleError_Limit, /**< The limited number of handles has been reached */ dvander@372: HandleError_Identity, /**< The identity token was not usable */ dvander@372: HandleError_Owner, /**< Owners do not match for this operation */ dvander@372: HandleError_Version, /**< Unrecognized security structure version */ dvander@372: HandleError_Parameter, /**< An invalid parameter was passed */ dvander@372: HandleError_NoInherit, /**< This type cannot be inherited */ dvander@324: }; dvander@324: dvander@324: /** dvander@372: * @brief Lists access rights specific to a type. dvander@324: */ dvander@324: enum HTypeAccessRight dvander@324: { dvander@372: HTypeAccess_Create = 0, /**< Handles of this type can be created (DEFAULT=false) */ dvander@372: HTypeAccess_Inherit, /**< Sub-types can inherit this type (DEFAULT=false) */ dvander@324: /* -------------- */ dvander@372: HTypeAccess_TOTAL, /**< Total number of type access rights */ dvander@324: }; dvander@324: dvander@324: /** dvander@372: * @brief Lists access rights specific to a Handle. dvander@372: * dvander@372: * These rights are exclusive. For example, you do not need "read" access to delete or clone. dvander@324: */ dvander@324: enum HandleAccessRight dvander@324: { dvander@372: HandleAccess_Read, /**< Can be read (DEFAULT=ident only) */ dvander@372: HandleAccess_Delete, /**< Can be deleted (DEFAULT=owner only) */ dvander@372: HandleAccess_Clone, /**< Can be cloned (DEFAULT=any) */ dvander@324: /* ------------- */ dvander@372: HandleAccess_TOTAL, /**< Total number of access rights */ dvander@324: }; dvander@324: dvander@372: /** Access is restricted to the identity */ dvander@372: #define HANDLE_RESTRICT_IDENTITY (1<<0) dvander@372: /** Access is restricted to the owner */ dvander@372: #define HANDLE_RESTRICT_OWNER (1<<1) dvander@324: dvander@324: /** dvander@372: * @brief This is used to define per-type access rights. dvander@324: */ dvander@324: struct TypeAccess dvander@324: { dvander@372: /** Constructor */ dvander@324: TypeAccess() dvander@324: { dvander@324: hsVersion = SMINTERFACE_HANDLESYSTEM_VERSION; dvander@324: } dvander@372: unsigned int hsVersion; /**< Handle API version */ dvander@372: IdentityToken_t *ident; /**< Identity owning this type */ dvander@372: bool access[HTypeAccess_TOTAL]; /**< Access array */ dvander@324: }; dvander@324: dvander@324: /** dvander@372: * @brief This is used to define per-Handle access rights. dvander@324: */ dvander@324: struct HandleAccess dvander@324: { dvander@372: /** Constructor */ dvander@324: HandleAccess() dvander@324: { dvander@324: hsVersion = SMINTERFACE_HANDLESYSTEM_VERSION; dvander@324: } dvander@372: unsigned int hsVersion; /**< Handle API version */ dvander@372: unsigned int access[HandleAccess_TOTAL]; /**< Access array */ dvander@324: }; dvander@324: dvander@324: /** dvander@372: * @brief This pair of tokens is used for identification. dvander@324: */ dvander@324: struct HandleSecurity dvander@324: { dvander@857: HandleSecurity() dvander@857: { dvander@857: } dvander@857: HandleSecurity(IdentityToken_t *owner, IdentityToken_t *identity) dvander@857: : pOwner(owner), pIdentity(identity) dvander@857: { dvander@857: } dvander@372: IdentityToken_t *pOwner; /**< Owner of the Handle */ dvander@372: IdentityToken_t *pIdentity; /**< Owner of the Type */ dvander@324: }; dvander@324: dvander@372: /** dvander@372: * @brief Hooks type-specific Handle operations. dvander@372: */ dvander@324: class IHandleTypeDispatch dvander@324: { dvander@324: public: dvander@372: /** Returns the Handle API version */ dvander@324: virtual unsigned int GetDispatchVersion() dvander@324: { dvander@324: return SMINTERFACE_HANDLESYSTEM_VERSION; dvander@324: } dvander@324: public: dvander@324: /** dvander@324: * @brief Called when destroying a handle. Must be implemented. dvander@324: */ dvander@324: virtual void OnHandleDestroy(HandleType_t type, void *object) =0; dvander@324: }; dvander@324: dvander@372: /** dvander@372: * @brief Provides functions for managing Handles. dvander@372: */ dvander@324: class IHandleSys : public SMInterface dvander@324: { dvander@324: public: dvander@324: virtual unsigned int GetInterfaceVersion() dvander@324: { dvander@324: return SMINTERFACE_HANDLESYSTEM_VERSION; dvander@324: } dvander@324: virtual const char *GetInterfaceName() dvander@324: { dvander@324: return SMINTERFACE_HANDLESYSTEM_NAME; dvander@324: } dvander@324: public: dvander@324: /** dvander@324: * @brief Creates a new Handle type. dvander@324: * NOTE: Currently, a child type may not have its own children. dvander@324: * NOTE: Handle names must be unique if not private. dvander@324: * dvander@324: * @param name Name of handle type (NULL or "" to be anonymous) dvander@324: * @param dispatch Pointer to a valid IHandleTypeDispatch object. dvander@324: * @param parent Parent handle to inherit from, 0 for none. dvander@324: * @param typeAccess Pointer to a TypeAccess object, NULL to use default dvander@324: * or inherited permissions. Pointer can be temporary. dvander@324: * @param hndlAccess Pointer to a HandleAccess object to define default dvander@324: * default permissions on each Handle. NULL to use default dvander@324: * permissions. dvander@324: * @param ident Security token for any permissions. If typeAccess is NULL, this dvander@324: * becomes the owning identity. dvander@324: * @param err Optional pointer to store an error code. dvander@324: * @return A new HandleType_t unique ID, or 0 on failure. dvander@324: */ dvander@324: virtual HandleType_t CreateType(const char *name, dvander@324: IHandleTypeDispatch *dispatch, dvander@324: HandleType_t parent, dvander@324: const TypeAccess *typeAccess, dvander@324: const HandleAccess *hndlAccess, dvander@324: IdentityToken_t *ident, dvander@324: HandleError *err) =0; dvander@324: dvander@324: /** dvander@324: * @brief Removes a handle type. dvander@324: * NOTE: This removes all child types. dvander@324: * dvander@324: * @param type Type chain to remove. dvander@324: * @param ident Identity token. Removal fails if the token does not match. dvander@324: * @return True on success, false on failure. dvander@324: */ dvander@324: virtual bool RemoveType(HandleType_t type, IdentityToken_t *ident) =0; dvander@324: dvander@324: /** dvander@324: * @brief Finds a handle type by name. dvander@324: * dvander@324: * @param name Name of handle type to find (anonymous not allowed). dvander@324: * @param type Address to store found handle in (if not found, undefined). dvander@324: * @return True if found, false otherwise. dvander@324: */ dvander@324: virtual bool FindHandleType(const char *name, HandleType_t *type) =0; dvander@324: dvander@324: /** dvander@324: * @brief Creates a new handle. dvander@324: * dvander@324: * @param type Type to use on the handle. dvander@324: * @param object Object to bind to the handle. dvander@324: * @param owner Owner of the new Handle (may be NULL). dvander@324: * @param ident Identity for type access if needed (may be NULL). dvander@324: * @param err Optional pointer to store an error code. dvander@324: * @return A new Handle_t, or 0 on failure. dvander@324: */ dvander@324: virtual Handle_t CreateHandle(HandleType_t type, dvander@324: void *object, dvander@324: IdentityToken_t *owner, dvander@324: IdentityToken_t *ident, dvander@324: HandleError *err) =0; dvander@324: dvander@324: /** dvander@324: * @brief Frees the memory associated with a handle and calls any destructors. dvander@324: * NOTE: This function will decrement the internal reference counter. It will dvander@324: * only perform any further action if the counter hits 0. dvander@324: * dvander@372: * @param handle Handle_t identifier to destroy. dvander@324: * @param pSecurity Security information struct (may be NULL). dvander@324: * @return A HandleError error code. dvander@324: */ dvander@324: virtual HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity) =0; dvander@324: dvander@324: /** dvander@324: * @brief Clones a handle by adding to its internal reference count. Its data, dvander@324: * type, and security permissions remain the same. dvander@324: * dvander@324: * @param handle Handle to duplicate. Any non-free handle target is valid. dvander@324: * @param newhandle Stores the duplicated handle in the pointer (must not be NULL). dvander@324: * @param newOwner New owner of cloned handle. dvander@324: * @param pSecurity Security information struct (may be NULL). dvander@324: * @return A HandleError error code. dvander@324: */ dvander@324: virtual HandleError CloneHandle(Handle_t handle, dvander@324: Handle_t *newhandle, dvander@324: IdentityToken_t *newOwner, dvander@324: const HandleSecurity *pSecurity) =0; dvander@324: dvander@324: /** dvander@324: * @brief Retrieves the contents of a handle. dvander@324: * dvander@324: * @param handle Handle_t from which to retrieve contents. dvander@324: * @param type Expected type to read as. 0 ignores typing rules. dvander@324: * @param pSecurity Security information struct (may be NULL). dvander@324: * @param object Optional address to store object in. dvander@324: * @return HandleError error code. dvander@324: */ dvander@324: virtual HandleError ReadHandle(Handle_t handle, dvander@324: HandleType_t type, dvander@324: const HandleSecurity *pSecurity, dvander@324: void **object) =0; dvander@324: dvander@324: /** dvander@324: * @brief Sets access permissions on one or more structures. dvander@324: * dvander@324: * @param pTypeAccess Optional TypeAccess buffer to initialize with the default values. dvander@324: * @param pHandleAccess Optional HandleAccess buffer to initialize with the default values. dvander@335: * @return True on success, false if version is unsupported. dvander@324: */ dvander@324: virtual bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess) =0; dvander@528: dvander@528: /** dvander@528: * @brief Creates a new handle. dvander@528: * dvander@528: * @param type Type to use on the handle. dvander@528: * @param object Object to bind to the handle. dvander@528: * @param pSec Security pointer; pOwner is written as the owner, dvander@528: * pIdent is used as the parent identity for authorization. dvander@528: * @param pAccess Access right descriptor for the Handle; NULL for type defaults. dvander@528: * @param err Optional pointer to store an error code. dvander@528: * @return A new Handle_t, or 0 on failure. dvander@528: */ dvander@528: virtual Handle_t CreateHandleEx(HandleType_t type, dvander@528: void *object, dvander@528: const HandleSecurity *pSec, dvander@528: const HandleAccess *pAccess, dvander@528: HandleError *err) =0; dvander@324: }; ds@432: } dvander@324: dvander@324: #endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_