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