core/logic/HandleSys.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 4175 3ae24e84c028
permissions -rw-r--r--
Update CS:GO team score gamedata.
     1 /**
     2  * vim: set ts=4 sw=4 tw=99 noet :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "HandleSys.h"
    33 #include <assert.h>
    34 #include <string.h>
    35 #include "common_logic.h"
    36 #include "ShareSys.h"
    37 #include "ExtensionSys.h"
    38 #include "PluginSys.h"
    39 
    40 HandleSystem g_HandleSys;
    41 
    42 QHandle *ignore_handle;
    43 
    44 inline HandleType_t TypeParent(HandleType_t type)
    45 {
    46 	return (type & ~HANDLESYS_SUBTYPE_MASK);
    47 }
    48 
    49 inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
    50 {
    51 	return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
    52 }
    53 
    54 HandleSystem::HandleSystem()
    55 {
    56 	m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
    57 	memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
    58 
    59 	m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
    60 	memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
    61 
    62 	m_TypeTail = 0;
    63 }
    64 
    65 HandleSystem::~HandleSystem()
    66 {
    67 	delete [] m_Handles;
    68 	delete [] m_Types;
    69 }
    70 
    71 
    72 HandleType_t HandleSystem::CreateType(const char *name, 
    73 									  IHandleTypeDispatch *dispatch, 
    74 									  HandleType_t parent, 
    75 									  const TypeAccess *typeAccess, 
    76 									  const HandleAccess *hndlAccess, 
    77 									  IdentityToken_t *ident,
    78 									  HandleError *err)
    79 {
    80 	if (!dispatch)
    81 	{
    82 		if (err)
    83 		{
    84 			*err = HandleError_Parameter;
    85 		}
    86 		return 0;
    87 	}
    88 
    89 	if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
    90 	{
    91 		if (err)
    92 		{
    93 			*err = HandleError_Version;
    94 		}
    95 		return 0;
    96 	}
    97 
    98 	if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
    99 	{
   100 		if (err)
   101 		{
   102 			*err = HandleError_Version;
   103 		}
   104 		return 0;
   105 	}
   106 
   107 	bool isChild = false;
   108 
   109 	if (parent != 0)
   110 	{
   111 		isChild = true;
   112 		if (parent & HANDLESYS_SUBTYPE_MASK)
   113 		{
   114 			if (err)
   115 			{
   116 				*err = HandleError_NoInherit;
   117 			}
   118 			return 0;
   119 		}
   120 		if (parent >= HANDLESYS_TYPEARRAY_SIZE
   121 			|| m_Types[parent].dispatch == NULL)
   122 		{
   123 			if (err)
   124 			{
   125 				*err = HandleError_Parameter;
   126 			}
   127 			return 0;
   128 		}
   129 		if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
   130 			&& (m_Types[parent].typeSec.ident != ident))
   131 		{
   132 			if (err)
   133 			{
   134 				*err = HandleError_Access;
   135 			}
   136 			return 0;
   137 		}
   138 	}
   139 
   140 	if (name && name[0] != '\0')
   141 	{
   142 		if (m_TypeLookup.contains(name))
   143 		{
   144 			if (err)
   145 				*err = HandleError_Parameter;
   146 			return 0;
   147 		}
   148 	}
   149 
   150 	unsigned int index;
   151 
   152 	if (isChild)
   153 	{
   154 		QHandleType *pParent = &m_Types[parent];
   155 		if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
   156 		{
   157 			if (err)
   158 			{
   159 				*err = HandleError_Limit;
   160 			}
   161 			return 0;
   162 		}
   163 		index = 0;
   164 		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
   165 		{
   166 			if (m_Types[parent + i].dispatch == NULL)
   167 			{
   168 				index = parent + i;
   169 				break;
   170 			}
   171 		}
   172 		if (!index)
   173 		{
   174 			if (err)
   175 			{
   176 				*err = HandleError_Limit;
   177 			}
   178 			return 0;
   179 		}
   180 		pParent->children++;
   181 	} else {
   182 		if (m_FreeTypes == 0)
   183 		{
   184 			/* Reserve another index */
   185 			if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
   186 			{
   187 				if (err)
   188 				{
   189 					*err = HandleError_Limit;
   190 				}
   191 				return 0;
   192 			} else {
   193 				m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
   194 				index = m_TypeTail;
   195 			}
   196 		} else {
   197 			/* The "free array" is compacted into the normal array for easiness */
   198 			index = m_Types[m_FreeTypes--].freeID;
   199 		}
   200 	}
   201 
   202 	QHandleType *pType = &m_Types[index];
   203 	
   204 	pType->dispatch = dispatch;
   205 	if (name && name[0] != '\0')
   206 	{
   207 		pType->name = new ke::AString(name);
   208 		m_TypeLookup.insert(name, pType);
   209 	}
   210 
   211 	pType->opened = 0;
   212 
   213 	if (typeAccess)
   214 	{
   215 		pType->typeSec = *typeAccess;
   216 	} else {
   217 		InitAccessDefaults(&pType->typeSec, NULL);
   218 		pType->typeSec.ident = ident;
   219 	}
   220 
   221 	if (hndlAccess)
   222 	{
   223 		pType->hndlSec = *hndlAccess;
   224 	} else {
   225 		InitAccessDefaults(NULL, &pType->hndlSec);
   226 	}
   227 
   228 	if (!isChild)
   229 	{
   230 		pType->children = 0;
   231 	}
   232 
   233 	return index;
   234 }
   235 
   236 bool HandleSystem::FindHandleType(const char *name, HandleType_t *aResult)
   237 {
   238 	QHandleType *type;
   239 	if (!m_TypeLookup.retrieve(name, &type))
   240 		return false;
   241 
   242 	if (aResult)
   243 		*aResult = type - m_Types;
   244 
   245 	return true;
   246 }
   247 
   248 HandleError HandleSystem::TryAllocHandle(unsigned int *handle)
   249 {
   250 	if (m_FreeHandles == 0)
   251 	{
   252 		if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
   253 		{
   254 			return HandleError_Limit;;
   255 		}
   256 		*handle = ++m_HandleTail;
   257 	}
   258 	else
   259 	{
   260 		*handle = m_Handles[m_FreeHandles--].freeID;
   261 	}
   262 
   263 	return HandleError_None;
   264 }
   265 
   266 HandleError HandleSystem::MakePrimHandle(HandleType_t type, 
   267 						   QHandle **in_pHandle, 
   268 						   unsigned int *in_index, 
   269 						   Handle_t *in_handle,
   270 						   IdentityToken_t *owner,
   271 						   bool identity)
   272 {
   273 	HandleError err;
   274 	unsigned int owner_index = 0;
   275 
   276 	if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
   277 	{
   278 		return HandleError_Identity;
   279 	}
   280 
   281 	unsigned int handle;
   282 	if ((err = TryAllocHandle(&handle)) != HandleError_None)
   283 	{
   284 		if (!TryAndFreeSomeHandles()
   285 			|| (err = TryAllocHandle(&handle)) != HandleError_None)
   286 		{
   287 			return err;
   288 		}
   289 	}
   290 
   291 	QHandle *pHandle = &m_Handles[handle];
   292 	
   293 	assert(pHandle->set == false);
   294 
   295 	if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
   296 	{
   297 		m_HSerial = 1;
   298 	}
   299 
   300 	/* Set essential information */
   301 	pHandle->set = identity ? HandleSet_Identity : HandleSet_Used;
   302 	pHandle->refcount = 1;
   303 	pHandle->type = type;
   304 	pHandle->serial = m_HSerial;
   305 	pHandle->owner = owner;
   306 	pHandle->ch_next = 0;
   307 	pHandle->access_special = false;
   308 	pHandle->is_destroying = false;
   309 
   310 	/* Create the hash value */
   311 	Handle_t hash = pHandle->serial;
   312 	hash <<= 16;
   313 	hash |= handle;
   314 
   315 	/* Add a reference count to the type */
   316 	m_Types[type].opened++;
   317 
   318 	/* Output */
   319 	*in_pHandle = pHandle;
   320 	*in_index = handle;
   321 	*in_handle = hash;
   322 
   323 	/* Decode the identity token 
   324 	 * For now, we don't allow nested ownership
   325 	 */
   326 	if (owner && !identity)
   327 	{
   328 		QHandle *pIdentity = &m_Handles[owner_index];
   329 		if (pIdentity->ch_prev == 0)
   330 		{
   331 			pIdentity->ch_prev = handle;
   332 			pIdentity->ch_next = handle;
   333 			pHandle->ch_prev = 0;
   334 		}
   335 		else
   336 		{
   337 			/* Link previous node to us (forward) */
   338 			m_Handles[pIdentity->ch_next].ch_next = handle;
   339 			/* Link us to previous node (backwards) */
   340 			pHandle->ch_prev = pIdentity->ch_next;
   341 			/* Set new tail */
   342 			pIdentity->ch_next = handle;
   343 		}
   344 		pIdentity->refcount++;
   345 	}
   346 	else
   347 	{
   348 		pHandle->ch_prev = 0;
   349 	}
   350 
   351 	return HandleError_None;
   352 }
   353 
   354 void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
   355 {
   356 	if (!type
   357 		|| type >= HANDLESYS_TYPEARRAY_SIZE
   358 		|| m_Types[type].dispatch == NULL)
   359 	{
   360 		return;
   361 	}
   362 
   363 	m_Types[type].typeSec.ident = pToken;
   364 }
   365 
   366 Handle_t HandleSystem::CreateHandleInt(HandleType_t type, 
   367 									   void *object, 
   368 									   const HandleSecurity *pSec,
   369 									   HandleError *err, 
   370 									   const HandleAccess *pAccess,
   371 									   bool identity)
   372 {
   373 	IdentityToken_t *ident;
   374 	IdentityToken_t *owner;
   375 
   376 	if (pSec)
   377 	{
   378 		ident = pSec->pIdentity;
   379 		owner = pSec->pOwner;
   380 	} else {
   381 		ident = NULL;
   382 		owner = NULL;
   383 	}
   384 
   385 	if (!type 
   386 		|| type >= HANDLESYS_TYPEARRAY_SIZE
   387 		|| m_Types[type].dispatch == NULL)
   388 	{
   389 		if (err)
   390 		{
   391 			*err = HandleError_Parameter;
   392 		}
   393 		return 0;
   394 	}
   395 
   396 	/* Check to see if we're allowed to create this handle type */
   397 	QHandleType *pType = &m_Types[type];
   398 	if (!pType->typeSec.access[HTypeAccess_Create]
   399 	&& (!pType->typeSec.ident
   400 		|| pType->typeSec.ident != ident))
   401 	{
   402 		if (err)
   403 		{
   404 			*err = HandleError_Access;
   405 		}
   406 		return 0;
   407 	}
   408 
   409 	unsigned int index;
   410 	Handle_t handle;
   411 	QHandle *pHandle;
   412 	HandleError _err;
   413 
   414 	if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
   415 	{
   416 		if (err)
   417 		{
   418 			*err = _err;
   419 		}
   420 		return 0;
   421 	}
   422 
   423 	if (pAccess)
   424 	{
   425 		pHandle->access_special = true;
   426 		pHandle->sec = *pAccess;
   427 	}
   428 
   429 	pHandle->object = object;
   430 	pHandle->clone = 0;
   431 
   432 	return handle;
   433 }
   434 
   435 Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err)
   436 {
   437 	return CreateHandleInt(type, object, pSec, err, pAccess, false);
   438 }
   439 
   440 Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
   441 {
   442 	HandleSecurity sec;
   443 
   444 	sec.pIdentity = ident;
   445 	sec.pOwner = owner;
   446 
   447 	return CreateHandleEx(type, object, &sec, NULL, err);
   448 }
   449 
   450 bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
   451 {
   452 	/* Check the type inheritance */
   453 	if (intype & HANDLESYS_SUBTYPE_MASK)
   454 	{
   455 		if (intype != outtype
   456 			&& (TypeParent(intype) != TypeParent(outtype)))
   457 		{
   458 			return false;
   459 		}
   460 	} else {
   461 		if (intype != outtype)
   462 		{
   463 			return false;
   464 		}
   465 	}
   466 
   467 	return true;
   468 }
   469 
   470 HandleError HandleSystem::GetHandle(Handle_t handle,
   471 									IdentityToken_t *ident, 
   472 									QHandle **in_pHandle, 
   473 									unsigned int *in_index,
   474 									bool ignoreFree)
   475 {
   476 	unsigned int serial = (handle >> 16);
   477 	unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
   478 
   479 	if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
   480 	{
   481 		return HandleError_Index;
   482 	}
   483 
   484 	QHandle *pHandle = &m_Handles[index];
   485 
   486 	if (!pHandle->set
   487 		|| (pHandle->set == HandleSet_Freed && !ignoreFree))
   488 	{
   489 		return HandleError_Freed;
   490 	} else if (pHandle->set == HandleSet_Identity
   491 			   && ident != g_ShareSys.GetIdentRoot())
   492 	{
   493 		/* Only IdentityHandle() can read this! */
   494 		return HandleError_Identity;
   495 	}
   496 	if (pHandle->serial != serial)
   497 	{
   498 		return HandleError_Changed;
   499 	}
   500 
   501 	*in_pHandle = pHandle;
   502 	*in_index = index;
   503 
   504 	return HandleError_None;
   505 }
   506 
   507 bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity)
   508 {
   509 	QHandleType *pType = &m_Types[pHandle->type];
   510 	unsigned int access;
   511 
   512 	if (pHandle->access_special)
   513 	{
   514 		access = pHandle->sec.access[right];
   515 	} else {
   516 		access = pType->hndlSec.access[right];
   517 	}
   518 
   519 	/* Check if the type's identity matches */
   520 	if (access & HANDLE_RESTRICT_IDENTITY)
   521 	{
   522 		IdentityToken_t *owner = pType->typeSec.ident;
   523 		if (!owner
   524 			|| (!pSecurity || pSecurity->pIdentity != owner))
   525 		{
   526 			return false;
   527 		}
   528 	}
   529 
   530 	/* Check if the owner is allowed */
   531 	if (access & HANDLE_RESTRICT_OWNER)
   532 	{
   533 		IdentityToken_t *owner = pHandle->owner;
   534 		if (owner
   535 			&& (!pSecurity || pSecurity->pOwner != owner))
   536 		{
   537 			return false;
   538 		}
   539 	}
   540 
   541 	return true;
   542 }
   543 
   544 HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner)
   545 {
   546 	/* Get a new Handle ID */
   547 	unsigned int new_index;
   548 	QHandle *pNewHandle;
   549 	Handle_t new_handle;
   550 	HandleError err;
   551 
   552 	if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
   553 	{
   554 		return err;
   555 	}
   556 
   557 	/* Assign permissions from parent */
   558 	if (pHandle->access_special)
   559 	{
   560 		pNewHandle->access_special = true;
   561 		pNewHandle->sec = pHandle->sec;
   562 	}
   563 
   564 	pNewHandle->clone = index;
   565 	pNewHandle->object = NULL;
   566 	pHandle->refcount++;
   567 
   568 	*newhandle = new_handle;
   569 
   570 	return HandleError_None;
   571 }
   572 
   573 HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity)
   574 {
   575 	HandleError err;
   576 	QHandle *pHandle;
   577 	unsigned int index;
   578 	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   579 
   580 	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   581 	{
   582 		return err;
   583 	}
   584 
   585 	/* Identities cannot be cloned */
   586 	if (pHandle->set == HandleSet_Identity)
   587 	{
   588 		return HandleError_Identity;
   589 	}
   590 
   591 	/* Check if the handle can be cloned */
   592 	if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity))
   593 	{
   594 		return HandleError_Access;
   595 	}
   596 
   597 	/* Make sure we're not cloning a clone */
   598 	if (pHandle->clone)
   599 	{
   600 		QHandle *pParent = &m_Handles[pHandle->clone];
   601 		return CloneHandle(pParent, pHandle->clone, newhandle, newOwner);
   602 	}
   603 
   604 	return CloneHandle(pHandle, index, newhandle, newOwner);
   605 }
   606 
   607 Handle_t HandleSystem::FastCloneHandle(QHandle *pHandle, unsigned int index)
   608 {
   609 	if (pHandle->clone)
   610 		return FastCloneHandle(&m_Handles[pHandle->clone], pHandle->clone);
   611 
   612 	Handle_t hndl;
   613 	if (CloneHandle(pHandle, index, &hndl, g_pCoreIdent) != HandleError_None)
   614 		return BAD_HANDLE;
   615 
   616 	return hndl;
   617 }
   618 
   619 Handle_t HandleSystem::FastCloneHandle(Handle_t hndl)
   620 {
   621 	QHandle *pHandle;
   622 	unsigned int index;
   623 
   624 	GetHandleUnchecked(hndl, pHandle, index);
   625 
   626 	return FastCloneHandle(pHandle, index);
   627 }
   628 
   629 void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index)
   630 {
   631 #ifndef NDEBUG
   632 	unsigned int serial = (hndl >> 16);
   633 #endif
   634 	index = (hndl & HANDLESYS_HANDLE_MASK);
   635 
   636 	assert(index != 0 && index <= m_HandleTail && index < HANDLESYS_MAX_HANDLES);
   637 
   638 	pHandle = &m_Handles[index];
   639 
   640 	assert(pHandle->set && pHandle->set != HandleSet_Freed);
   641 	assert(pHandle->serial == serial);
   642 }
   643 
   644 HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
   645 {
   646 	if (pHandle->is_destroying)
   647 	{
   648 		/* Someone tried to free this recursively.  
   649 		 * We'll just ignore this safely.
   650 		 */
   651 		return HandleError_None;
   652 	}
   653 
   654 	QHandleType *pType = &m_Types[pHandle->type];
   655 
   656 	if (pHandle->clone)
   657 	{
   658 		/* If we're a clone, decrease the parent reference count */
   659 		QHandle *pMaster;
   660 		unsigned int master;
   661 
   662 		/* Note that if we ever have per-handle security, we would need to re-check
   663 		* the access on this Handle. */
   664 		master = pHandle->clone;
   665 		pMaster = &m_Handles[master];
   666 
   667 		/* Release the clone now */
   668 		pHandle->is_destroying = true;
   669 		ReleasePrimHandle(index);
   670 
   671 		/* Decrement the master's reference count */
   672 		if (--pMaster->refcount == 0)
   673 		{
   674 			/* Type should be the same but do this anyway... */
   675 			pType = &m_Types[pMaster->type];
   676 			pMaster->is_destroying = true;
   677 			if (pMaster->object)
   678 			{
   679 				pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
   680 			}
   681 			ReleasePrimHandle(master);
   682 		}
   683 	} else if (pHandle->set == HandleSet_Identity) {
   684 		/* If we're an identity, skip all this stuff!
   685 		 * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
   686 		 */
   687 		pHandle->is_destroying = true;
   688 		ReleasePrimHandle(index);
   689 	} else {
   690 		/* Decrement, free if necessary */
   691 		if (--pHandle->refcount == 0)
   692 		{
   693 			pHandle->is_destroying = true;
   694 			if (pHandle->object)
   695 			{
   696 				pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
   697 			}
   698 			ReleasePrimHandle(index);
   699 		} else {
   700 			/* We must be cloned, so mark ourselves as freed */
   701 			pHandle->set = HandleSet_Freed;
   702 			/* Now, unlink us, so we're not being tracked by the owner */
   703 			if (pHandle->owner)
   704 			{
   705 				UnlinkHandleFromOwner(pHandle, index);
   706 			}
   707 		}
   708 	}
   709 
   710 	return HandleError_None;
   711 }
   712 
   713 HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity)
   714 {
   715 	unsigned int index;
   716 	QHandle *pHandle;
   717 	HandleError err;
   718 	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   719 
   720 	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   721 	{
   722 		return err;
   723 	}
   724 
   725 	if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity))
   726 	{
   727 		return HandleError_Access;
   728 	}
   729 
   730 	return FreeHandle(pHandle, index);
   731 }
   732 
   733 HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object)
   734 {
   735 	unsigned int index;
   736 	QHandle *pHandle;
   737 	HandleError err;
   738 	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   739 
   740 	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   741 	{
   742 		return err;
   743 	}
   744 
   745 	if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity))
   746 	{
   747 		return HandleError_Access;
   748 	}
   749 
   750 	/* Check the type inheritance */
   751 	if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
   752 	{
   753 		if (pHandle->type != type
   754 			&& (TypeParent(pHandle->type) != TypeParent(type)))
   755 		{
   756 			return HandleError_Type;
   757 		}
   758 	} else if (type) {
   759 		if (pHandle->type != type)
   760 		{
   761 			return HandleError_Type;
   762 		}
   763 	}
   764 
   765 	if (object)
   766 	{
   767 		/* if we're a clone, the rules change - object is ONLY in our reference */
   768 		if (pHandle->clone)
   769 		{
   770 			pHandle = &m_Handles[pHandle->clone];
   771 		}
   772 		*object = pHandle->object;
   773 	}
   774 
   775 	return HandleError_None;
   776 }
   777 
   778 void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
   779 {
   780 	/* Unlink us if necessary */
   781 	unsigned int ident_index;
   782 	if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
   783 	{
   784 		/* Uh-oh! */
   785 		assert(pHandle->owner == 0);
   786 		return;
   787 	}
   788 
   789 	pHandle->owner = NULL;
   790 
   791 	/* Note that since 0 is an invalid handle, if any of these links are 0,
   792 	* the data can still be set.
   793 	*/
   794 	QHandle *pIdentity = &m_Handles[ident_index];
   795 
   796 	/* Unlink case: We're the head AND tail node */
   797 	if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
   798 	{
   799 		pIdentity->ch_prev = 0;
   800 		pIdentity->ch_next = 0;
   801 	}
   802 	/* Unlink case: We're the head node */
   803 	else if (index == pIdentity->ch_prev) {
   804 		/* Link us to the next in the chain */
   805 		pIdentity->ch_prev = pHandle->ch_next;
   806 		/* Patch up the previous link */
   807 		m_Handles[pHandle->ch_next].ch_prev = 0;
   808 	}
   809 	/* Unlink case: We're the tail node */
   810 	else if (index == pIdentity->ch_next) {
   811 		/* Link us to the previous in the chain */
   812 		pIdentity->ch_next = pHandle->ch_prev;
   813 		/* Patch up the next link */
   814 		m_Handles[pHandle->ch_prev].ch_next = 0;
   815 	}
   816 	/* Unlink case: We're in the middle! */
   817 	else {
   818 		/* Patch the forward reference */
   819 		m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
   820 		/* Patch the backward reference */
   821 		m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
   822 	}
   823 
   824 	/* Lastly, decrease the reference count */
   825 	pIdentity->refcount--;
   826 }
   827 
   828 void HandleSystem::ReleasePrimHandle(unsigned int index)
   829 {
   830 	QHandle *pHandle = &m_Handles[index];
   831 	HandleSet set = pHandle->set;
   832 
   833 	if (pHandle->owner && (set != HandleSet_Identity))
   834 	{
   835 		UnlinkHandleFromOwner(pHandle, index);
   836 	}
   837 
   838 	/* Were we an identity ourself? */
   839 	QHandle *pLocal;
   840 	if (set == HandleSet_Identity)
   841 	{
   842 		/* Extra work to do.  We need to find everything connected to this identity and release it. */
   843 		unsigned int ch_index;
   844 #if defined _DEBUG
   845 		unsigned int old_index = 0;
   846 #endif
   847 		while ((ch_index = pHandle->ch_next) != 0)
   848 		{
   849 			pLocal = &m_Handles[ch_index];
   850 #if defined _DEBUG
   851 			assert(old_index != ch_index);
   852 			assert(pLocal->set == HandleSet_Used);
   853 			old_index = ch_index;
   854 #endif
   855 			FreeHandle(pLocal, ch_index);
   856 		}
   857 	}
   858 
   859 	pHandle->set = HandleSet_None;
   860 	m_Types[pHandle->type].opened--;
   861 	m_Handles[++m_FreeHandles].freeID = index;
   862 }
   863 
   864 bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
   865 {
   866 	if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
   867 	{
   868 		return false;
   869 	}
   870 
   871 	QHandleType *pType = &m_Types[type];
   872 
   873 	if (pType->typeSec.ident
   874 		&& pType->typeSec.ident != ident)
   875 	{
   876 		return false;
   877 	}
   878 
   879 	if (pType->dispatch == NULL)
   880 	{
   881 		return false;
   882 	}
   883 
   884 	/* Remove children if we have to */
   885 	if (!(type & HANDLESYS_SUBTYPE_MASK))
   886 	{
   887 		QHandleType *childType;
   888 		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
   889 		{
   890 			childType = &m_Types[type + i];
   891 			if (childType->dispatch)
   892 			{
   893 				RemoveType(type + i, childType->typeSec.ident);
   894 			}
   895 		}
   896 		/* Link us into the free chain */
   897 		m_Types[++m_FreeTypes].freeID = type;
   898 	}
   899 
   900 	/* Make sure nothing is using this type. */
   901 	if (pType->opened)
   902 	{
   903 		QHandle *pHandle;
   904 		for (unsigned int i=1; i<=m_HandleTail; i++)
   905 		{
   906 			pHandle = &m_Handles[i];
   907 			if (!pHandle->set || pHandle->type != type)
   908 			{
   909 				continue;
   910 			}
   911 
   912 			FreeHandle(pHandle, i);
   913 
   914 			if (pType->opened == 0)
   915 			{
   916 				break;
   917 			}
   918 		}
   919 	}
   920 
   921 	/* Invalidate the type now */
   922 	pType->dispatch = NULL;
   923 
   924 	/* Remove it from the type cache. */
   925 	if (pType->name)
   926 		m_TypeLookup.remove(pType->name->chars());
   927 
   928 	return true;
   929 }
   930 
   931 bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
   932 {
   933 	if (pTypeAccess)
   934 	{
   935 		if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   936 		{
   937 			return false;
   938 		}
   939 		pTypeAccess->access[HTypeAccess_Create] = false;
   940 		pTypeAccess->access[HTypeAccess_Inherit] = false;
   941 		pTypeAccess->ident = NULL;
   942 	}
   943 
   944 	if (pHandleAccess)
   945 	{
   946 		if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   947 		{
   948 			return false;
   949 		}
   950 
   951 		pHandleAccess->access[HandleAccess_Clone] = 0;
   952 		pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
   953 		pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;
   954 	}
   955 
   956 	return true;
   957 }
   958 
   959 #define HANDLE_LOG_VERY_BAD(message, ...) \
   960 	smcore.LogFatal(message, ##__VA_ARGS__); \
   961 	smcore.LogError(message, ##__VA_ARGS__);
   962 
   963 bool HandleSystem::TryAndFreeSomeHandles()
   964 {
   965 	IPlugin *highest_owner = NULL;
   966 	unsigned int highest_handle_count = 0;
   967 
   968 	/* Search all plugins */
   969 	for (IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator(); pl_iter->MorePlugins(); pl_iter->NextPlugin())
   970 	{
   971 		IPlugin *plugin = pl_iter->GetPlugin();
   972 		IdentityToken_t *identity = plugin->GetIdentity();
   973 		unsigned int handle_count = 0;
   974 
   975 		if (identity == NULL)
   976 		{
   977 			continue;
   978 		}
   979 
   980 		/* Search all handles */
   981 		for (unsigned int i = 1; i <= m_HandleTail; i++)
   982 		{
   983 			if (m_Handles[i].set != HandleSet_Used)
   984 			{
   985 				continue;
   986 			}
   987 			if (m_Handles[i].owner == identity)
   988 			{
   989 				handle_count++;
   990 			}
   991 		}
   992 
   993 		if (handle_count > highest_handle_count)
   994 		{
   995 			highest_owner = plugin;
   996 			highest_handle_count = handle_count;
   997 		}
   998 	}
   999 
  1000 	if (highest_owner == NULL || highest_handle_count == 0)
  1001 	{
  1002 		return false;
  1003 	}
  1004 
  1005 	HANDLE_LOG_VERY_BAD("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
  1006 	HANDLE_LOG_VERY_BAD("[SM] Unloading plugin to free %d handles.", highest_handle_count);
  1007 	HANDLE_LOG_VERY_BAD("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
  1008 	HANDLE_LOG_VERY_BAD("--------------------------------------------------------------------------");
  1009 
  1010 	const IdentityToken_t *pIdentity = highest_owner->GetIdentity();
  1011 	unsigned int total = 0, highest_index = 0, total_size = 0, size;
  1012 	unsigned int * pCount = new unsigned int[HANDLESYS_TYPEARRAY_SIZE+1];
  1013 	memset(pCount, 0, ((HANDLESYS_TYPEARRAY_SIZE + 1) * sizeof(unsigned int)));
  1014 
  1015 	for (unsigned int i = 1; i <= m_HandleTail; ++i)
  1016 	{
  1017 		const QHandle &Handle = m_Handles[i];
  1018 		if (Handle.set != HandleSet_Used || Handle.owner != pIdentity)
  1019 		{
  1020 			continue;
  1021 		}
  1022 
  1023 		++pCount[Handle.type];
  1024 		++total;
  1025 
  1026 		if (Handle.type >= highest_index)
  1027 		{
  1028 			highest_index = ((Handle.type) + 1);
  1029 		}
  1030 
  1031 		if (Handle.clone != 0)
  1032 		{
  1033 			continue;
  1034 		}
  1035 
  1036 		if (m_Types[Handle.type].dispatch->GetHandleApproxSize(Handle.type, Handle.object, &size))
  1037 		{
  1038 			total_size += size;
  1039 		}
  1040 	}
  1041 
  1042 	const char * pTypeName = NULL;
  1043 
  1044 	for (unsigned int i = 0; i < highest_index; ++i)
  1045 	{
  1046 		if (pCount[i] == 0)
  1047 		{
  1048 			continue; /* We may have gaps, it's fine. */
  1049 		}
  1050 
  1051 		if (m_Types[i].name)
  1052 			pTypeName = m_Types[i].name->chars();
  1053 		else
  1054 			pTypeName = "ANON";
  1055 
  1056 		HANDLE_LOG_VERY_BAD("Type\t%-20.20s|\tCount\t%u", pTypeName, pCount[i]);
  1057 	}
  1058 
  1059 	HANDLE_LOG_VERY_BAD("-- Approximately %d bytes of memory are in use by (%u) Handles.\n", total_size, total);
  1060 	delete [] pCount;
  1061 
  1062 	highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
  1063 
  1064 	return scripts->UnloadPlugin(highest_owner);
  1065 }
  1066 
  1067 void HandleSystem::Dump(HANDLE_REPORTER rep)
  1068 {
  1069 	unsigned int total_size = 0;
  1070 	rep("%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory");
  1071 	rep("--------------------------------------------------------------------------");
  1072 	for (unsigned int i = 1; i <= m_HandleTail; i++)
  1073 	{
  1074 		if (m_Handles[i].set != HandleSet_Used)
  1075 		{
  1076 			continue;
  1077 		}
  1078 		/* Get the index */
  1079 		unsigned int index = (m_Handles[i].serial << 16) | i;
  1080 		/* Determine the owner */
  1081 		const char *owner = "UNKNOWN";
  1082 		if (m_Handles[i].owner)
  1083 		{
  1084 			IdentityToken_t *pOwner = m_Handles[i].owner;
  1085 			if (pOwner == g_pCoreIdent)
  1086 			{
  1087 				owner = "CORE";
  1088 			}
  1089 			else if (pOwner == scripts->GetIdentity())
  1090 			{
  1091 				owner = "PLUGINSYS";
  1092 			}
  1093 			else
  1094 			{
  1095 				IExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
  1096 				if (ext)
  1097 				{
  1098 					owner = ext->GetFilename();
  1099 				}
  1100 				else
  1101 				{
  1102 					SMPlugin *pPlugin = scripts->FindPluginByIdentity(pOwner);
  1103 					if (pPlugin)
  1104 					{
  1105 						owner = pPlugin->GetFilename();
  1106 					}
  1107 				}
  1108 			}
  1109 		}
  1110 		else
  1111 		{
  1112 			owner = "NONE";
  1113 		}
  1114 		const char *type = "ANON";
  1115 		QHandleType *pType = &m_Types[m_Handles[i].type];
  1116 		unsigned int size = 0;
  1117 		unsigned int parentIdx;
  1118 		bool bresult;
  1119 		if (pType->name)
  1120 			type = pType->name->chars();
  1121 
  1122 		if ((parentIdx = m_Handles[i].clone) != 0)
  1123 		{
  1124 			if (m_Handles[parentIdx].refcount > 0)
  1125 			{
  1126 				size = 0;
  1127 				bresult = true;
  1128 			}
  1129 			else
  1130 			{
  1131 				bresult = pType->dispatch->GetHandleApproxSize(m_Handles[parentIdx].type, m_Handles[parentIdx].object, &size);
  1132 			}
  1133 		}
  1134 		else
  1135 		{
  1136 			bresult = pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size);
  1137 		}
  1138 
  1139 		if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
  1140 			|| !bresult)
  1141 		{
  1142 			rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1");
  1143 		}
  1144 		else
  1145 		{
  1146 			char buffer[32];
  1147 			smcore.Format(buffer, sizeof(buffer), "%d", size);
  1148 			rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
  1149 			total_size += size;
  1150 		}
  1151 	}
  1152 	rep("-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
  1153 }
  1154