core/smn_core.cpp
author David Anderson <dvander@alliedmods.net>
Sun Aug 26 17:41:02 2007 +0000 (2007-08-26)
changeset 1369 bd9ccced1b1a
parent 1359 c93c61f32568
child 1371 d207f0e17532
permissions -rw-r--r--
fixed amb834 - command callbacks could potentially occur on invalid clients in very rare cases
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 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 <time.h>
    33 #include <string.h>
    34 #include <stdlib.h>
    35 #include "sm_stringutil.h"
    36 #include "sm_globals.h"
    37 #include "sourcemod.h"
    38 #include "PluginSys.h"
    39 #include "HandleSys.h"
    40 #include "LibrarySys.h"
    41 
    42 #if defined PLATFORM_WINDOWS
    43 #include <windows.h>
    44 #elif defined PLATFORM_LINUX
    45 #include <limits.h>
    46 #include <unistd.h>
    47 #include <sys/times.h>
    48 #endif
    49 
    50 HandleType_t g_PlIter;
    51 ConVar sm_datetime_format("sm_datetime_format", "%m/%d/%Y - %H:%M:%S", 0, "Default formatting time rules");
    52 
    53 class CoreNativeHelpers : 
    54 	public SMGlobalClass,
    55 	public IHandleTypeDispatch
    56 {
    57 public:
    58 	void OnSourceModAllInitialized()
    59 	{
    60 		HandleAccess hacc;
    61 		g_HandleSys.InitAccessDefaults(NULL,  &hacc);
    62 		hacc.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
    63 
    64 		g_PlIter = g_HandleSys.CreateType("PluginIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    65 	}
    66 	void OnHandleDestroy(HandleType_t type, void *object)
    67 	{
    68 		IPluginIterator *iter = (IPluginIterator *)object;
    69 		iter->Release();
    70 	}
    71 	void OnSourceModShutdown()
    72 	{
    73 		g_HandleSys.RemoveType(g_PlIter, g_pCoreIdent);
    74 	}
    75 } g_CoreNativeHelpers;
    76 
    77 
    78 static cell_t ThrowError(IPluginContext *pContext, const cell_t *params)
    79 {
    80 	char buffer[512];
    81 
    82 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
    83 
    84 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
    85 
    86 	if (pContext->GetContext()->n_err == SP_ERROR_NONE)
    87 	{
    88 		pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", buffer);
    89 	}
    90 
    91 	return 0;
    92 }
    93 
    94 static cell_t GetTime(IPluginContext *pContext, const cell_t *params)
    95 {
    96 	time_t t = time(NULL);
    97 	cell_t *addr;
    98 	pContext->LocalToPhysAddr(params[1], &addr);
    99 
   100 	*(time_t *)addr = t;
   101 
   102 	return static_cast<cell_t>(t);
   103 }
   104 
   105 #if defined SUBPLATFORM_SECURECRT
   106 void _ignore_invalid_parameter(
   107 						const wchar_t * expression,
   108 						const wchar_t * function, 
   109 						const wchar_t * file, 
   110 						unsigned int line,
   111 						uintptr_t pReserved
   112 						)
   113 {
   114 	/* Wow we don't care, thanks Microsoft. */
   115 }
   116 #endif
   117 
   118 static cell_t FormatTime(IPluginContext *pContext, const cell_t *params)
   119 {
   120 	char *format, *buffer;
   121 	pContext->LocalToString(params[1], &buffer);
   122 	pContext->LocalToStringNULL(params[3], &format);
   123 
   124 	if (format == NULL)
   125 	{
   126 		format = const_cast<char *>(sm_datetime_format.GetString());
   127 	}
   128 
   129 #if defined SUBPLATFORM_SECURECRT
   130 	_invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
   131 #endif
   132 
   133 	time_t t = (params[4] == -1) ? time(NULL) : (time_t)params[4];
   134 	size_t written = strftime(buffer, params[2], format, localtime(&t));
   135 
   136 #if defined SUBPLATFORM_SECURECRT
   137 	_set_invalid_parameter_handler(handler);
   138 #endif
   139 
   140 	if (params[2] && format[0] != '\0' && !written)
   141 	{
   142 		pContext->ThrowNativeError("Invalid time format or buffer too small");
   143 		return 0;
   144 	}
   145 
   146 	return 1;
   147 }
   148 
   149 static cell_t GetPluginIterator(IPluginContext *pContext, const cell_t *params)
   150 {
   151 	IPluginIterator *iter = g_PluginSys.GetPluginIterator();
   152 
   153 	Handle_t hndl = g_HandleSys.CreateHandle(g_PlIter, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
   154 
   155 	if (hndl == BAD_HANDLE)
   156 	{
   157 		iter->Release();
   158 	}
   159 
   160 	return hndl;
   161 }
   162 
   163 static cell_t MorePlugins(IPluginContext *pContext, const cell_t *params)
   164 {
   165 	Handle_t hndl = (Handle_t)params[1];
   166 	HandleError err;
   167 	IPluginIterator *pIter;
   168 
   169 	HandleSecurity sec;
   170 	sec.pIdentity = g_pCoreIdent;
   171 	sec.pOwner = pContext->GetIdentity();
   172 
   173 	if ((err=g_HandleSys.ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None)
   174 	{
   175 		return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
   176 	}
   177 
   178 	return pIter->MorePlugins() ? 1 : 0;
   179 }
   180 
   181 static cell_t ReadPlugin(IPluginContext *pContext, const cell_t *params)
   182 {
   183 	Handle_t hndl = (Handle_t)params[1];
   184 	HandleError err;
   185 	IPluginIterator *pIter;
   186 
   187 	HandleSecurity sec;
   188 	sec.pIdentity = g_pCoreIdent;
   189 	sec.pOwner = pContext->GetIdentity();
   190 
   191 	if ((err=g_HandleSys.ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None)
   192 	{
   193 		return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
   194 	}
   195 
   196 	CPlugin *pPlugin = (CPlugin *)pIter->GetPlugin();
   197 	if (!pPlugin)
   198 	{
   199 		return BAD_HANDLE;
   200 	}
   201 
   202 	pIter->NextPlugin();
   203 
   204 	return pPlugin->GetMyHandle();
   205 }
   206 
   207 CPlugin *GetPluginFromHandle(IPluginContext *pContext, Handle_t hndl)
   208 {
   209 	if (hndl == BAD_HANDLE)
   210 	{
   211 		return g_PluginSys.GetPluginByCtx(pContext->GetContext());
   212 	} else {
   213 		HandleError err;
   214 		CPlugin *pPlugin = (CPlugin *)g_PluginSys.PluginFromHandle(hndl, &err);
   215 		if (!pPlugin)
   216 		{
   217 			pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
   218 		}
   219 		return pPlugin;
   220 	}
   221 }
   222 
   223 static cell_t GetPluginStatus(IPluginContext *pContext, const cell_t *params)
   224 {
   225 	CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
   226 	if (!pPlugin)
   227 	{
   228 		return 0;
   229 	}
   230 
   231 	return pPlugin->GetStatus();
   232 }
   233 
   234 static cell_t GetPluginFilename(IPluginContext *pContext, const cell_t *params)
   235 {
   236 	CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
   237 	if (!pPlugin)
   238 	{
   239 		return 0;
   240 	}
   241 
   242 	pContext->StringToLocalUTF8(params[2], params[3], pPlugin->GetFilename(), NULL);
   243 
   244 	return 1;
   245 }
   246 
   247 static cell_t IsPluginDebugging(IPluginContext *pContext, const cell_t *params)
   248 {
   249 	CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
   250 	if (!pPlugin)
   251 	{
   252 		return 0;
   253 	}
   254 
   255 	return pPlugin->IsDebugging() ? 1 : 0;
   256 }
   257 
   258 /* Local to plugins only */
   259 enum PluginInfo
   260 {
   261 	PlInfo_Name,			/**< Plugin name */
   262 	PlInfo_Author,			/**< Plugin author */
   263 	PlInfo_Description,		/**< Plugin description */
   264 	PlInfo_Version,			/**< Plugin verison */
   265 	PlInfo_URL,				/**< Plugin URL */
   266 };
   267 
   268 static cell_t GetPluginInfo(IPluginContext *pContext, const cell_t *params)
   269 {
   270 	CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
   271 	if (!pPlugin)
   272 	{
   273 		return 0;
   274 	}
   275 
   276 	const sm_plugininfo_t *info = pPlugin->GetPublicInfo();
   277 
   278 	if (!info)
   279 	{
   280 		return 0;
   281 	}
   282 
   283 	const char *str = NULL;
   284 
   285 	switch ((PluginInfo)params[2])
   286 	{
   287 	case PlInfo_Name:
   288 		{
   289 			str = info->name;
   290 			break;
   291 		}
   292 	case PlInfo_Author:
   293 		{
   294 			str = info->author;
   295 			break;
   296 		}
   297 	case PlInfo_Description:
   298 		{
   299 			str = info->description;
   300 			break;
   301 		}
   302 	case PlInfo_Version:
   303 		{
   304 			str = info->version;
   305 			break;
   306 		}
   307 	case PlInfo_URL:
   308 		{
   309 			str = info->url;
   310 			break;
   311 		}
   312 	}
   313 
   314 	if (!str || str[0] == '\0')
   315 	{
   316 		return 0;
   317 	}
   318 
   319 	pContext->StringToLocalUTF8(params[3], params[4], str, NULL);
   320 
   321 	return 1;
   322 }
   323 
   324 static cell_t SetFailState(IPluginContext *pContext, const cell_t *params)
   325 {
   326 	char *str;
   327 	pContext->LocalToString(params[1], &str);
   328 
   329 	CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
   330 	pPlugin->SetErrorState(Plugin_Error, "%s", str);
   331 
   332 	return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", str);
   333 }
   334 
   335 static cell_t GetSysTickCount(IPluginContext *pContext, const cell_t *params)
   336 {
   337 #if defined PLATFORM_WINDOWS
   338 	return (cell_t)GetTickCount();
   339 #elif defined PLATFORM_LINUX
   340 	tms tm;
   341 	clock_t ticks = times(&tm);
   342 	long ticks_per_sec = sysconf(_SC_CLK_TCK);
   343 	double fticks = (double)ticks / (double)ticks_per_sec;
   344 	fticks *= 1000.0f;
   345 	if (fticks > INT_MAX)
   346 	{
   347 		double r = (int)(fticks / INT_MAX) * (double)INT_MAX;
   348 		fticks -= r;
   349 	}
   350 	return (cell_t)fticks;
   351 #endif
   352 }
   353 
   354 static cell_t AutoExecConfig(IPluginContext *pContext, const cell_t *params)
   355 {
   356 	CPlugin *plugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
   357 
   358 	char *cfg, *folder;
   359 	pContext->LocalToString(params[2], &cfg);
   360 	pContext->LocalToString(params[3], &folder);
   361 
   362 	if (cfg[0] == '\0')
   363 	{
   364 		static char temp_str[255];
   365 		static char temp_file[PLATFORM_MAX_PATH];
   366 		char *ptr;
   367 
   368 		g_LibSys.GetFileFromPath(temp_str, sizeof(temp_str), plugin->GetFilename());
   369 		if ((ptr = strstr(temp_str, ".smx")) != NULL)
   370 		{
   371 			*ptr = '\0';
   372 		}
   373 
   374 		/* We have the raw filename! */
   375 		UTIL_Format(temp_file, sizeof(temp_file), "plugin.%s", temp_str);
   376 		cfg = temp_file;
   377 	}
   378 
   379 	plugin->AddConfig(params[1] ? true : false, cfg, folder);
   380 
   381 	return 1;
   382 }
   383 
   384 static cell_t MarkNativeAsOptional(IPluginContext *pContext, const cell_t *params)
   385 {
   386 	char *name;
   387 	uint32_t idx;
   388 	sp_context_t *ctx = pContext->GetContext();
   389 
   390 	pContext->LocalToString(params[1], &name);
   391 	if (pContext->FindNativeByName(name, &idx) != SP_ERROR_NONE)
   392 	{
   393 		/* Oops! This HAS to silently fail! */
   394 		return 0;
   395 	}
   396 
   397 	ctx->natives[idx].flags |= SP_NTVFLAG_OPTIONAL;
   398 
   399 	return 1;
   400 }
   401 
   402 static cell_t RegPluginLibrary(IPluginContext *pContext, const cell_t *params)
   403 {
   404 	char *name;
   405 	CPlugin *pl = g_PluginSys.GetPluginByCtx(pContext->GetContext());
   406 
   407 	pContext->LocalToString(params[1], &name);
   408 
   409 	pl->AddLibrary(name);
   410 
   411 	return 1;
   412 }
   413 
   414 static cell_t LibraryExists(IPluginContext *pContext, const cell_t *params)
   415 {
   416 	char *str;
   417 	pContext->LocalToString(params[1], &str);
   418 
   419 	return g_PluginSys.LibraryExists(str) ? 1 : 0;
   420 }
   421 
   422 REGISTER_NATIVES(coreNatives)
   423 {
   424 	{"AutoExecConfig",			AutoExecConfig},
   425 	{"GetPluginFilename",		GetPluginFilename},
   426 	{"GetPluginInfo",			GetPluginInfo},
   427 	{"GetPluginIterator",		GetPluginIterator},
   428 	{"GetPluginStatus",			GetPluginStatus},
   429 	{"GetSysTickCount",			GetSysTickCount},
   430 	{"GetTime",					GetTime},
   431 	{"IsPluginDebugging",		IsPluginDebugging},
   432 	{"MorePlugins",				MorePlugins},
   433 	{"ReadPlugin",				ReadPlugin},
   434 	{"ThrowError",				ThrowError},
   435 	{"SetFailState",			SetFailState},
   436 	{"FormatTime",				FormatTime},
   437 	{"MarkNativeAsOptional",	MarkNativeAsOptional},
   438 	{"RegPluginLibrary",		RegPluginLibrary},
   439 	{"LibraryExists",			LibraryExists},
   440 	{NULL,						NULL},
   441 };