1.1 --- a/core/systems/HandleSys.cpp Wed Nov 19 02:14:43 2008 -0600
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1076 +0,0 @@
1.4 -/**
1.5 - * vim: set ts=4 :
1.6 - * =============================================================================
1.7 - * SourceMod
1.8 - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 - * =============================================================================
1.10 - *
1.11 - * This program is free software; you can redistribute it and/or modify it under
1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
1.13 - * Free Software Foundation.
1.14 - *
1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 - * details.
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License along with
1.21 - * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 - *
1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 - * by the Valve Corporation. You must obey the GNU General Public License in
1.27 - * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 - * this exception to all derivative works. AlliedModders LLC defines further
1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 - * or <http://www.sourcemod.net/license.php>.
1.31 - *
1.32 - * Version: $Id$
1.33 - */
1.34 -
1.35 -#include "HandleSys.h"
1.36 -#include "ShareSys.h"
1.37 -#include "PluginSys.h"
1.38 -#include "ExtensionSys.h"
1.39 -#include "Logger.h"
1.40 -#include <assert.h>
1.41 -#include <string.h>
1.42 -#include "sm_stringutil.h"
1.43 -
1.44 -HandleSystem g_HandleSys;
1.45 -
1.46 -QHandle *ignore_handle;
1.47 -
1.48 -inline HandleType_t TypeParent(HandleType_t type)
1.49 -{
1.50 - return (type & ~HANDLESYS_SUBTYPE_MASK);
1.51 -}
1.52 -
1.53 -inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
1.54 -{
1.55 - return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
1.56 -}
1.57 -
1.58 -HandleSystem::HandleSystem()
1.59 -{
1.60 - m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
1.61 - memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
1.62 -
1.63 - m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
1.64 - memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
1.65 -
1.66 - m_TypeLookup = sm_trie_create();
1.67 - m_strtab = new BaseStringTable(512);
1.68 -
1.69 - m_TypeTail = 0;
1.70 -}
1.71 -
1.72 -HandleSystem::~HandleSystem()
1.73 -{
1.74 - delete [] m_Handles;
1.75 - delete [] m_Types;
1.76 - sm_trie_destroy(m_TypeLookup);
1.77 - delete m_strtab;
1.78 -}
1.79 -
1.80 -
1.81 -HandleType_t HandleSystem::CreateType(const char *name,
1.82 - IHandleTypeDispatch *dispatch,
1.83 - HandleType_t parent,
1.84 - const TypeAccess *typeAccess,
1.85 - const HandleAccess *hndlAccess,
1.86 - IdentityToken_t *ident,
1.87 - HandleError *err)
1.88 -{
1.89 - if (!dispatch)
1.90 - {
1.91 - if (err)
1.92 - {
1.93 - *err = HandleError_Parameter;
1.94 - }
1.95 - return 0;
1.96 - }
1.97 -
1.98 - if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
1.99 - {
1.100 - if (err)
1.101 - {
1.102 - *err = HandleError_Version;
1.103 - }
1.104 - return 0;
1.105 - }
1.106 -
1.107 - if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
1.108 - {
1.109 - if (err)
1.110 - {
1.111 - *err = HandleError_Version;
1.112 - }
1.113 - return 0;
1.114 - }
1.115 -
1.116 - bool isChild = false;
1.117 -
1.118 - if (parent != 0)
1.119 - {
1.120 - isChild = true;
1.121 - if (parent & HANDLESYS_SUBTYPE_MASK)
1.122 - {
1.123 - if (err)
1.124 - {
1.125 - *err = HandleError_NoInherit;
1.126 - }
1.127 - return 0;
1.128 - }
1.129 - if (parent >= HANDLESYS_TYPEARRAY_SIZE
1.130 - || m_Types[parent].dispatch == NULL)
1.131 - {
1.132 - if (err)
1.133 - {
1.134 - *err = HandleError_Parameter;
1.135 - }
1.136 - return 0;
1.137 - }
1.138 - if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
1.139 - && (m_Types[parent].typeSec.ident != ident))
1.140 - {
1.141 - if (err)
1.142 - {
1.143 - *err = HandleError_Access;
1.144 - }
1.145 - return 0;
1.146 - }
1.147 - }
1.148 -
1.149 - if (name && name[0] != '\0')
1.150 - {
1.151 - if (sm_trie_retrieve(m_TypeLookup, name, NULL))
1.152 - {
1.153 - if (err)
1.154 - {
1.155 - *err = HandleError_Parameter;
1.156 - }
1.157 - return 0;
1.158 - }
1.159 - }
1.160 -
1.161 - unsigned int index;
1.162 -
1.163 - if (isChild)
1.164 - {
1.165 - QHandleType *pParent = &m_Types[parent];
1.166 - if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
1.167 - {
1.168 - if (err)
1.169 - {
1.170 - *err = HandleError_Limit;
1.171 - }
1.172 - return 0;
1.173 - }
1.174 - index = 0;
1.175 - for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
1.176 - {
1.177 - if (m_Types[parent + i].dispatch == NULL)
1.178 - {
1.179 - index = parent + i;
1.180 - break;
1.181 - }
1.182 - }
1.183 - if (!index)
1.184 - {
1.185 - if (err)
1.186 - {
1.187 - *err = HandleError_Limit;
1.188 - }
1.189 - return 0;
1.190 - }
1.191 - pParent->children++;
1.192 - } else {
1.193 - if (m_FreeTypes == 0)
1.194 - {
1.195 - /* Reserve another index */
1.196 - if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
1.197 - {
1.198 - if (err)
1.199 - {
1.200 - *err = HandleError_Limit;
1.201 - }
1.202 - return 0;
1.203 - } else {
1.204 - m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
1.205 - index = m_TypeTail;
1.206 - }
1.207 - } else {
1.208 - /* The "free array" is compacted into the normal array for easiness */
1.209 - index = m_Types[m_FreeTypes--].freeID;
1.210 - }
1.211 - }
1.212 -
1.213 - QHandleType *pType = &m_Types[index];
1.214 -
1.215 - pType->dispatch = dispatch;
1.216 - if (name && name[0] != '\0')
1.217 - {
1.218 - pType->nameIdx = m_strtab->AddString(name);
1.219 - sm_trie_insert(m_TypeLookup, name, (void *)pType);
1.220 - } else {
1.221 - pType->nameIdx = -1;
1.222 - }
1.223 -
1.224 - pType->opened = 0;
1.225 -
1.226 - if (typeAccess)
1.227 - {
1.228 - pType->typeSec = *typeAccess;
1.229 - } else {
1.230 - InitAccessDefaults(&pType->typeSec, NULL);
1.231 - pType->typeSec.ident = ident;
1.232 - }
1.233 -
1.234 - if (hndlAccess)
1.235 - {
1.236 - pType->hndlSec = *hndlAccess;
1.237 - } else {
1.238 - InitAccessDefaults(NULL, &pType->hndlSec);
1.239 - }
1.240 -
1.241 - if (!isChild)
1.242 - {
1.243 - pType->children = 0;
1.244 - }
1.245 -
1.246 - return index;
1.247 -}
1.248 -
1.249 -bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
1.250 -{
1.251 - QHandleType *_type;
1.252 -
1.253 - if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
1.254 - {
1.255 - return false;
1.256 - }
1.257 -
1.258 - unsigned int offset = _type - m_Types;
1.259 -
1.260 - if (type)
1.261 - {
1.262 - *type = offset;
1.263 - }
1.264 -
1.265 - return true;
1.266 -}
1.267 -
1.268 -HandleError HandleSystem::TryAllocHandle(unsigned int *handle)
1.269 -{
1.270 - if (m_FreeHandles == 0)
1.271 - {
1.272 - if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
1.273 - {
1.274 - return HandleError_Limit;;
1.275 - }
1.276 - *handle = ++m_HandleTail;
1.277 - }
1.278 - else
1.279 - {
1.280 - *handle = m_Handles[m_FreeHandles--].freeID;
1.281 - }
1.282 -
1.283 - return HandleError_None;
1.284 -}
1.285 -
1.286 -HandleError HandleSystem::MakePrimHandle(HandleType_t type,
1.287 - QHandle **in_pHandle,
1.288 - unsigned int *in_index,
1.289 - Handle_t *in_handle,
1.290 - IdentityToken_t *owner,
1.291 - bool identity)
1.292 -{
1.293 - HandleError err;
1.294 - unsigned int owner_index = 0;
1.295 -
1.296 - if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
1.297 - {
1.298 - return HandleError_Identity;
1.299 - }
1.300 -
1.301 - unsigned int handle;
1.302 - if ((err = TryAllocHandle(&handle)) != HandleError_None)
1.303 - {
1.304 - if (!TryAndFreeSomeHandles()
1.305 - || (err = TryAllocHandle(&handle)) != HandleError_None)
1.306 - {
1.307 - return err;
1.308 - }
1.309 - }
1.310 -
1.311 - QHandle *pHandle = &m_Handles[handle];
1.312 -
1.313 - assert(pHandle->set == false);
1.314 -
1.315 - if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
1.316 - {
1.317 - m_HSerial = 1;
1.318 - }
1.319 -
1.320 - /* Set essential information */
1.321 - pHandle->set = identity ? HandleSet_Identity : HandleSet_Used;
1.322 - pHandle->refcount = 1;
1.323 - pHandle->type = type;
1.324 - pHandle->serial = m_HSerial;
1.325 - pHandle->owner = owner;
1.326 - pHandle->ch_next = 0;
1.327 - pHandle->access_special = false;
1.328 - pHandle->is_destroying = false;
1.329 -
1.330 - /* Create the hash value */
1.331 - Handle_t hash = pHandle->serial;
1.332 - hash <<= 16;
1.333 - hash |= handle;
1.334 -
1.335 - /* Add a reference count to the type */
1.336 - m_Types[type].opened++;
1.337 -
1.338 - /* Output */
1.339 - *in_pHandle = pHandle;
1.340 - *in_index = handle;
1.341 - *in_handle = hash;
1.342 -
1.343 - /* Decode the identity token
1.344 - * For now, we don't allow nested ownership
1.345 - */
1.346 - if (owner && !identity)
1.347 - {
1.348 - QHandle *pIdentity = &m_Handles[owner_index];
1.349 - if (pIdentity->ch_prev == 0)
1.350 - {
1.351 - pIdentity->ch_prev = handle;
1.352 - pIdentity->ch_next = handle;
1.353 - pHandle->ch_prev = 0;
1.354 - }
1.355 - else
1.356 - {
1.357 - /* Link previous node to us (forward) */
1.358 - m_Handles[pIdentity->ch_next].ch_next = handle;
1.359 - /* Link us to previous node (backwards) */
1.360 - pHandle->ch_prev = pIdentity->ch_next;
1.361 - /* Set new tail */
1.362 - pIdentity->ch_next = handle;
1.363 - }
1.364 - pIdentity->refcount++;
1.365 - }
1.366 - else
1.367 - {
1.368 - pHandle->ch_prev = 0;
1.369 - }
1.370 -
1.371 - return HandleError_None;
1.372 -}
1.373 -
1.374 -void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
1.375 -{
1.376 - if (!type
1.377 - || type >= HANDLESYS_TYPEARRAY_SIZE
1.378 - || m_Types[type].dispatch == NULL)
1.379 - {
1.380 - return;
1.381 - }
1.382 -
1.383 - m_Types[type].typeSec.ident = pToken;
1.384 -}
1.385 -
1.386 -Handle_t HandleSystem::CreateHandleInt(HandleType_t type,
1.387 - void *object,
1.388 - const HandleSecurity *pSec,
1.389 - HandleError *err,
1.390 - const HandleAccess *pAccess,
1.391 - bool identity)
1.392 -{
1.393 - IdentityToken_t *ident;
1.394 - IdentityToken_t *owner;
1.395 -
1.396 - if (pSec)
1.397 - {
1.398 - ident = pSec->pIdentity;
1.399 - owner = pSec->pOwner;
1.400 - } else {
1.401 - ident = NULL;
1.402 - owner = NULL;
1.403 - }
1.404 -
1.405 - if (!type
1.406 - || type >= HANDLESYS_TYPEARRAY_SIZE
1.407 - || m_Types[type].dispatch == NULL)
1.408 - {
1.409 - if (err)
1.410 - {
1.411 - *err = HandleError_Parameter;
1.412 - }
1.413 - return 0;
1.414 - }
1.415 -
1.416 - /* Check to see if we're allowed to create this handle type */
1.417 - QHandleType *pType = &m_Types[type];
1.418 - if (!pType->typeSec.access[HTypeAccess_Create]
1.419 - && (!pType->typeSec.ident
1.420 - || pType->typeSec.ident != ident))
1.421 - {
1.422 - if (err)
1.423 - {
1.424 - *err = HandleError_Access;
1.425 - }
1.426 - return 0;
1.427 - }
1.428 -
1.429 - unsigned int index;
1.430 - Handle_t handle;
1.431 - QHandle *pHandle;
1.432 - HandleError _err;
1.433 -
1.434 - if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
1.435 - {
1.436 - if (err)
1.437 - {
1.438 - *err = _err;
1.439 - }
1.440 - return 0;
1.441 - }
1.442 -
1.443 - if (pAccess)
1.444 - {
1.445 - pHandle->access_special = true;
1.446 - pHandle->sec = *pAccess;
1.447 - }
1.448 -
1.449 - pHandle->object = object;
1.450 - pHandle->clone = 0;
1.451 -
1.452 - return handle;
1.453 -}
1.454 -
1.455 -Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err)
1.456 -{
1.457 - return CreateHandleInt(type, object, pSec, err, pAccess, false);
1.458 -}
1.459 -
1.460 -Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
1.461 -{
1.462 - HandleSecurity sec;
1.463 -
1.464 - sec.pIdentity = ident;
1.465 - sec.pOwner = owner;
1.466 -
1.467 - return CreateHandleEx(type, object, &sec, NULL, err);
1.468 -}
1.469 -
1.470 -bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
1.471 -{
1.472 - /* Check the type inheritance */
1.473 - if (intype & HANDLESYS_SUBTYPE_MASK)
1.474 - {
1.475 - if (intype != outtype
1.476 - && (TypeParent(intype) != TypeParent(outtype)))
1.477 - {
1.478 - return false;
1.479 - }
1.480 - } else {
1.481 - if (intype != outtype)
1.482 - {
1.483 - return false;
1.484 - }
1.485 - }
1.486 -
1.487 - return true;
1.488 -}
1.489 -
1.490 -HandleError HandleSystem::GetHandle(Handle_t handle,
1.491 - IdentityToken_t *ident,
1.492 - QHandle **in_pHandle,
1.493 - unsigned int *in_index,
1.494 - bool ignoreFree)
1.495 -{
1.496 - unsigned int serial = (handle >> 16);
1.497 - unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
1.498 -
1.499 - if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
1.500 - {
1.501 - return HandleError_Index;
1.502 - }
1.503 -
1.504 - QHandle *pHandle = &m_Handles[index];
1.505 -
1.506 - if (!pHandle->set
1.507 - || (pHandle->set == HandleSet_Freed && !ignoreFree))
1.508 - {
1.509 - return HandleError_Freed;
1.510 - } else if (pHandle->set == HandleSet_Identity
1.511 - && ident != g_ShareSys.GetIdentRoot())
1.512 - {
1.513 - /* Only IdentityHandle() can read this! */
1.514 - return HandleError_Identity;
1.515 - }
1.516 - if (pHandle->serial != serial)
1.517 - {
1.518 - return HandleError_Changed;
1.519 - }
1.520 -
1.521 - *in_pHandle = pHandle;
1.522 - *in_index = index;
1.523 -
1.524 - return HandleError_None;
1.525 -}
1.526 -
1.527 -bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity)
1.528 -{
1.529 - QHandleType *pType = &m_Types[pHandle->type];
1.530 - unsigned int access;
1.531 -
1.532 - if (pHandle->access_special)
1.533 - {
1.534 - access = pHandle->sec.access[right];
1.535 - } else {
1.536 - access = pType->hndlSec.access[right];
1.537 - }
1.538 -
1.539 - /* Check if the type's identity matches */
1.540 - if (access & HANDLE_RESTRICT_IDENTITY)
1.541 - {
1.542 - IdentityToken_t *owner = pType->typeSec.ident;
1.543 - if (!owner
1.544 - || (!pSecurity || pSecurity->pIdentity != owner))
1.545 - {
1.546 - return false;
1.547 - }
1.548 - }
1.549 -
1.550 - /* Check if the owner is allowed */
1.551 - if (access & HANDLE_RESTRICT_OWNER)
1.552 - {
1.553 - IdentityToken_t *owner = pHandle->owner;
1.554 - if (owner
1.555 - && (!pSecurity || pSecurity->pOwner != owner))
1.556 - {
1.557 - return false;
1.558 - }
1.559 - }
1.560 -
1.561 - return true;
1.562 -}
1.563 -
1.564 -HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner)
1.565 -{
1.566 - /* Get a new Handle ID */
1.567 - unsigned int new_index;
1.568 - QHandle *pNewHandle;
1.569 - Handle_t new_handle;
1.570 - HandleError err;
1.571 -
1.572 - if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
1.573 - {
1.574 - return err;
1.575 - }
1.576 -
1.577 - /* Assign permissions from parent */
1.578 - if (pHandle->access_special)
1.579 - {
1.580 - pNewHandle->access_special = true;
1.581 - pNewHandle->sec = pHandle->sec;
1.582 - }
1.583 -
1.584 - pNewHandle->clone = index;
1.585 - pHandle->refcount++;
1.586 -
1.587 - *newhandle = new_handle;
1.588 -
1.589 - return HandleError_None;
1.590 -}
1.591 -
1.592 -HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity)
1.593 -{
1.594 - HandleError err;
1.595 - QHandle *pHandle;
1.596 - unsigned int index;
1.597 - IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
1.598 -
1.599 - if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
1.600 - {
1.601 - return err;
1.602 - }
1.603 -
1.604 - /* Identities cannot be cloned */
1.605 - if (pHandle->set == HandleSet_Identity)
1.606 - {
1.607 - return HandleError_Identity;
1.608 - }
1.609 -
1.610 - /* Check if the handle can be cloned */
1.611 - if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity))
1.612 - {
1.613 - return HandleError_Access;
1.614 - }
1.615 -
1.616 - /* Make sure we're not cloning a clone */
1.617 - if (pHandle->clone)
1.618 - {
1.619 - QHandle *pParent = &m_Handles[pHandle->clone];
1.620 - return CloneHandle(pParent, pHandle->clone, newhandle, newOwner);
1.621 - }
1.622 -
1.623 - return CloneHandle(pHandle, index, newhandle, newOwner);
1.624 -}
1.625 -
1.626 -HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
1.627 -{
1.628 - QHandleType *pType = &m_Types[pHandle->type];
1.629 -
1.630 - if (pHandle->clone)
1.631 - {
1.632 - /* If we're a clone, decrease the parent reference count */
1.633 - QHandle *pMaster;
1.634 - unsigned int master;
1.635 -
1.636 - /* Note that if we ever have per-handle security, we would need to re-check
1.637 - * the access on this Handle. */
1.638 - master = pHandle->clone;
1.639 - pMaster = &m_Handles[master];
1.640 -
1.641 - /* Release the clone now */
1.642 - ReleasePrimHandle(index);
1.643 -
1.644 - /* Decrement the master's reference count */
1.645 - if (--pMaster->refcount == 0)
1.646 - {
1.647 - /* Type should be the same but do this anyway... */
1.648 - pType = &m_Types[pMaster->type];
1.649 - pMaster->is_destroying = true;
1.650 - pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
1.651 - ReleasePrimHandle(master);
1.652 - }
1.653 - } else if (pHandle->set == HandleSet_Identity) {
1.654 - /* If we're an identity, skip all this stuff!
1.655 - * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
1.656 - */
1.657 - ReleasePrimHandle(index);
1.658 - } else {
1.659 - /* Decrement, free if necessary */
1.660 - if (--pHandle->refcount == 0)
1.661 - {
1.662 - pHandle->is_destroying = true;
1.663 - pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
1.664 - ReleasePrimHandle(index);
1.665 - } else {
1.666 - /* We must be cloned, so mark ourselves as freed */
1.667 - pHandle->set = HandleSet_Freed;
1.668 - /* Now, unlink us, so we're not being tracked by the owner */
1.669 - if (pHandle->owner)
1.670 - {
1.671 - UnlinkHandleFromOwner(pHandle, index);
1.672 - }
1.673 - }
1.674 - }
1.675 -
1.676 - return HandleError_None;
1.677 -}
1.678 -
1.679 -HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity)
1.680 -{
1.681 - unsigned int index;
1.682 - QHandle *pHandle;
1.683 - HandleError err;
1.684 - IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
1.685 -
1.686 - if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
1.687 - {
1.688 - return err;
1.689 - }
1.690 -
1.691 - if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity))
1.692 - {
1.693 - return HandleError_Access;
1.694 - }
1.695 -
1.696 - if (pHandle->is_destroying)
1.697 - {
1.698 - /* Someone tried to free this recursively.
1.699 - * We'll just ignore this safely.
1.700 - */
1.701 - return HandleError_None;
1.702 - }
1.703 -
1.704 - return FreeHandle(pHandle, index);
1.705 -}
1.706 -
1.707 -HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object)
1.708 -{
1.709 - unsigned int index;
1.710 - QHandle *pHandle;
1.711 - HandleError err;
1.712 - IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
1.713 -
1.714 - if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
1.715 - {
1.716 - return err;
1.717 - }
1.718 -
1.719 - if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity))
1.720 - {
1.721 - return HandleError_Access;
1.722 - }
1.723 -
1.724 - /* Check the type inheritance */
1.725 - if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
1.726 - {
1.727 - if (pHandle->type != type
1.728 - && (TypeParent(pHandle->type) != TypeParent(type)))
1.729 - {
1.730 - return HandleError_Type;
1.731 - }
1.732 - } else if (type) {
1.733 - if (pHandle->type != type)
1.734 - {
1.735 - return HandleError_Type;
1.736 - }
1.737 - }
1.738 -
1.739 - if (object)
1.740 - {
1.741 - /* if we're a clone, the rules change - object is ONLY in our reference */
1.742 - if (pHandle->clone)
1.743 - {
1.744 - pHandle = &m_Handles[pHandle->clone];
1.745 - }
1.746 - *object = pHandle->object;
1.747 - }
1.748 -
1.749 - return HandleError_None;
1.750 -}
1.751 -
1.752 -void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
1.753 -{
1.754 - /* Unlink us if necessary */
1.755 - unsigned int ident_index;
1.756 - if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
1.757 - {
1.758 - /* Uh-oh! */
1.759 - assert(pHandle->owner == 0);
1.760 - return;
1.761 - }
1.762 - /* Note that since 0 is an invalid handle, if any of these links are 0,
1.763 - * the data can still be set.
1.764 - */
1.765 - QHandle *pIdentity = &m_Handles[ident_index];
1.766 -
1.767 - /* Unlink case: We're the head AND tail node */
1.768 - if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
1.769 - {
1.770 - pIdentity->ch_prev = 0;
1.771 - pIdentity->ch_next = 0;
1.772 - }
1.773 - /* Unlink case: We're the head node */
1.774 - else if (index == pIdentity->ch_prev) {
1.775 - /* Link us to the next in the chain */
1.776 - pIdentity->ch_prev = pHandle->ch_next;
1.777 - /* Patch up the previous link */
1.778 - m_Handles[pHandle->ch_next].ch_prev = 0;
1.779 - }
1.780 - /* Unlink case: We're the tail node */
1.781 - else if (index == pIdentity->ch_next) {
1.782 - /* Link us to the previous in the chain */
1.783 - pIdentity->ch_next = pHandle->ch_prev;
1.784 - /* Patch up the next link */
1.785 - m_Handles[pHandle->ch_prev].ch_next = 0;
1.786 - }
1.787 - /* Unlink case: We're in the middle! */
1.788 - else {
1.789 - /* Patch the forward reference */
1.790 - m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
1.791 - /* Patch the backward reference */
1.792 - m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
1.793 - }
1.794 -
1.795 - /* Lastly, decrease the reference count */
1.796 - pIdentity->refcount--;
1.797 -}
1.798 -
1.799 -void HandleSystem::ReleasePrimHandle(unsigned int index)
1.800 -{
1.801 - QHandle *pHandle = &m_Handles[index];
1.802 - HandleSet set = pHandle->set;
1.803 -
1.804 - if (pHandle->owner && (set != HandleSet_Identity))
1.805 - {
1.806 - UnlinkHandleFromOwner(pHandle, index);
1.807 - }
1.808 -
1.809 - /* Were we an identity ourself? */
1.810 - QHandle *pLocal;
1.811 - if (set == HandleSet_Identity)
1.812 - {
1.813 - /* Extra work to do. We need to find everything connected to this identity and release it. */
1.814 - unsigned int ch_index;
1.815 -#if defined _DEBUG
1.816 - unsigned int old_index = 0;
1.817 -#endif
1.818 - while ((ch_index = pHandle->ch_next) != 0)
1.819 - {
1.820 - pLocal = &m_Handles[ch_index];
1.821 -#if defined _DEBUG
1.822 - assert(old_index != ch_index);
1.823 - assert(pLocal->set == HandleSet_Used);
1.824 - old_index = ch_index;
1.825 -#endif
1.826 - FreeHandle(pLocal, ch_index);
1.827 - }
1.828 - }
1.829 -
1.830 - pHandle->set = HandleSet_None;
1.831 - m_Types[pHandle->type].opened--;
1.832 - m_Handles[++m_FreeHandles].freeID = index;
1.833 -}
1.834 -
1.835 -bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
1.836 -{
1.837 - if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
1.838 - {
1.839 - return false;
1.840 - }
1.841 -
1.842 - QHandleType *pType = &m_Types[type];
1.843 -
1.844 - if (pType->typeSec.ident
1.845 - && pType->typeSec.ident != ident)
1.846 - {
1.847 - return false;
1.848 - }
1.849 -
1.850 - if (pType->dispatch == NULL)
1.851 - {
1.852 - return false;
1.853 - }
1.854 -
1.855 - /* Remove children if we have to */
1.856 - if (!(type & HANDLESYS_SUBTYPE_MASK))
1.857 - {
1.858 - QHandleType *childType;
1.859 - for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
1.860 - {
1.861 - childType = &m_Types[type + i];
1.862 - if (childType->dispatch)
1.863 - {
1.864 - RemoveType(type + i, childType->typeSec.ident);
1.865 - }
1.866 - }
1.867 - /* Link us into the free chain */
1.868 - m_Types[++m_FreeTypes].freeID = type;
1.869 - }
1.870 -
1.871 - /* Invalidate the type now */
1.872 - IHandleTypeDispatch *dispatch = pType->dispatch;
1.873 - pType->dispatch = NULL;
1.874 -
1.875 - /* Make sure nothing is using this type. */
1.876 - if (pType->opened)
1.877 - {
1.878 - QHandle *pHandle;
1.879 - for (unsigned int i=1; i<=m_HandleTail; i++)
1.880 - {
1.881 - pHandle = &m_Handles[i];
1.882 - if (!pHandle->set || pHandle->type != type)
1.883 - {
1.884 - continue;
1.885 - }
1.886 - if (pHandle->clone)
1.887 - {
1.888 - /* Get parent */
1.889 - QHandle *pOther = &m_Handles[pHandle->clone];
1.890 - if (--pOther->refcount == 0)
1.891 - {
1.892 - /* Free! */
1.893 - dispatch->OnHandleDestroy(type, pOther->object);
1.894 - ReleasePrimHandle(pHandle->clone);
1.895 - }
1.896 - /* Unlink ourselves since we don't have a reference count */
1.897 - ReleasePrimHandle(i);
1.898 - } else {
1.899 - /* If it's not a clone, we still have to check the reference count.
1.900 - * Either way, we'll be destroyed eventually because the handle types do not change.
1.901 - */
1.902 - if (--pHandle->refcount == 0)
1.903 - {
1.904 - /* Free! */
1.905 - dispatch->OnHandleDestroy(type, pHandle->object);
1.906 - ReleasePrimHandle(i);
1.907 - }
1.908 - }
1.909 - if (pType->opened == 0)
1.910 - {
1.911 - break;
1.912 - }
1.913 - }
1.914 - }
1.915 -
1.916 - /* Remove it from the type cache. */
1.917 - if (pType->nameIdx != -1)
1.918 - {
1.919 - const char *typeName;
1.920 -
1.921 - typeName = m_strtab->GetString(pType->nameIdx);
1.922 - sm_trie_delete(m_TypeLookup, typeName);
1.923 - }
1.924 -
1.925 - return true;
1.926 -}
1.927 -
1.928 -bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
1.929 -{
1.930 - if (pTypeAccess)
1.931 - {
1.932 - if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
1.933 - {
1.934 - return false;
1.935 - }
1.936 - pTypeAccess->access[HTypeAccess_Create] = false;
1.937 - pTypeAccess->access[HTypeAccess_Inherit] = false;
1.938 - pTypeAccess->ident = NULL;
1.939 - }
1.940 -
1.941 - if (pHandleAccess)
1.942 - {
1.943 - if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
1.944 - {
1.945 - return false;
1.946 - }
1.947 -
1.948 - pHandleAccess->access[HandleAccess_Clone] = 0;
1.949 - pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
1.950 - pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;
1.951 - }
1.952 -
1.953 - return true;
1.954 -}
1.955 -
1.956 -bool HandleSystem::TryAndFreeSomeHandles()
1.957 -{
1.958 - IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
1.959 - IPlugin *highest_owner = NULL;
1.960 - unsigned int highest_handle_count = 0;
1.961 -
1.962 - /* Search all plugins */
1.963 - while (pl_iter->MorePlugins())
1.964 - {
1.965 - IPlugin *plugin = pl_iter->GetPlugin();
1.966 - IdentityToken_t *identity = plugin->GetIdentity();
1.967 - unsigned int handle_count = 0;
1.968 -
1.969 - if (identity == NULL)
1.970 - {
1.971 - continue;
1.972 - }
1.973 -
1.974 - /* Search all handles */
1.975 - for (unsigned int i = 1; i <= m_HandleTail; i++)
1.976 - {
1.977 - if (m_Handles[i].set != HandleSet_Used)
1.978 - {
1.979 - continue;
1.980 - }
1.981 - if (m_Handles[i].owner == identity)
1.982 - {
1.983 - handle_count++;
1.984 - }
1.985 - }
1.986 -
1.987 - if (handle_count > highest_handle_count)
1.988 - {
1.989 - highest_owner = plugin;
1.990 - highest_handle_count = handle_count;
1.991 - }
1.992 -
1.993 - pl_iter->NextPlugin();
1.994 - }
1.995 -
1.996 - if (highest_owner == NULL || highest_handle_count == 0)
1.997 - {
1.998 - return false;
1.999 - }
1.1000 -
1.1001 - g_Logger.LogFatal("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
1.1002 - g_Logger.LogFatal("[SM] Reloading plugin to free %d handles.", highest_handle_count);
1.1003 - g_Logger.LogFatal("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
1.1004 -
1.1005 - highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
1.1006 -
1.1007 - return g_PluginSys.UnloadPlugin(highest_owner);
1.1008 -}
1.1009 -
1.1010 -void HandleSystem::Dump(HANDLE_REPORTER rep)
1.1011 -{
1.1012 - unsigned int total_size = 0;
1.1013 - rep("%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory");
1.1014 - rep("--------------------------------------------------------------------------");
1.1015 - for (unsigned int i = 1; i <= m_HandleTail; i++)
1.1016 - {
1.1017 - if (m_Handles[i].set != HandleSet_Used)
1.1018 - {
1.1019 - continue;
1.1020 - }
1.1021 - /* Get the index */
1.1022 - unsigned int index = (m_Handles[i].serial << 16) | i;
1.1023 - /* Determine the owner */
1.1024 - const char *owner = "UNKNOWN";
1.1025 - if (m_Handles[i].owner)
1.1026 - {
1.1027 - IdentityToken_t *pOwner = m_Handles[i].owner;
1.1028 - if (pOwner == g_pCoreIdent)
1.1029 - {
1.1030 - owner = "CORE";
1.1031 - }
1.1032 - else if (pOwner == g_PluginSys.GetIdentity())
1.1033 - {
1.1034 - owner = "PLUGINSYS";
1.1035 - }
1.1036 - else
1.1037 - {
1.1038 - CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
1.1039 - if (ext)
1.1040 - {
1.1041 - owner = ext->GetFilename();
1.1042 - }
1.1043 - else
1.1044 - {
1.1045 - CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner);
1.1046 - if (pPlugin)
1.1047 - {
1.1048 - owner = pPlugin->GetFilename();
1.1049 - }
1.1050 - }
1.1051 - }
1.1052 - }
1.1053 - else
1.1054 - {
1.1055 - owner = "NONE";
1.1056 - }
1.1057 - const char *type = "ANON";
1.1058 - QHandleType *pType = &m_Types[m_Handles[i].type];
1.1059 - unsigned int size = 0;
1.1060 - if (pType->nameIdx != -1)
1.1061 - {
1.1062 - type = m_strtab->GetString(pType->nameIdx);
1.1063 - }
1.1064 - if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
1.1065 - || !pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size))
1.1066 - {
1.1067 - rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1");
1.1068 - }
1.1069 - else
1.1070 - {
1.1071 - char buffer[32];
1.1072 - UTIL_Format(buffer, sizeof(buffer), "%d", size);
1.1073 - rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
1.1074 - total_size += size;
1.1075 - }
1.1076 - }
1.1077 - rep("-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
1.1078 -}
1.1079 -