Beispiel #1
0
static void Sphere_MainMonitorLoop()
{
	const char *m_sClassName = "Sphere";
	// Just make sure the main loop is alive every so often.
	// This should be the parent thread. try to restart it if it is not.
	while ( ! g_Serv.m_iExitFlag )
	{
		EXC_TRY("MainMonitorLoop");

		if ( g_Cfg.m_iFreezeRestartTime <= 0 )
		{
			DEBUG_ERR(("Freeze Restart Time cannot be cleared at run time\n"));
			g_Cfg.m_iFreezeRestartTime = 10;
		}

		EXC_SET("Sleep");
		// only sleep 1 second at a time, to avoid getting stuck here when closing
		// down with large m_iFreezeRestartTime values set
		for (int i = 0; i < g_Cfg.m_iFreezeRestartTime; ++i)
		{
			if ( g_Serv.m_iExitFlag )
				break;

#ifdef _WIN32
			NTWindow_OnTick(1000);
#else
			Sleep(1000);
#endif
		}

		EXC_SET("Checks");
		// Don't look for freezing when doing certain things.
		if ( g_Serv.IsLoading() || ! g_Cfg.m_fSecure || g_Serv.IsValidBusy() )
			continue;

		EXC_SET("Check Stuck");
#ifndef _DEBUG
		if (g_Main.checkStuck() == true)
			g_Log.Event(LOGL_CRIT, "'%s' thread hang, restarting...\n", g_Main.getName());
#endif
		EXC_CATCH;

		EXC_DEBUG_START;
		EXC_DEBUG_END;
	}

}
Beispiel #2
0
void Sphere_ExitServer()
{
	// Trigger server quit
	g_Serv.r_Call("f_onserver_exit", &g_Serv, NULL);

	g_Serv.SetServerMode(SERVMODE_Exiting);

#ifndef _MTNETWORK
	g_NetworkOut.waitForClose();
#else
	g_NetworkManager.stop();
#endif
	g_Main.waitForClose();
	g_PingServer.waitForClose();
	g_asyncHdb.waitForClose();
#if !defined(_WIN32) || defined(_LIBEV)
	if ( g_Cfg.m_fUseAsyncNetwork != 0 )
		g_NetworkEvent.waitForClose();
#endif
		
	g_Serv.SocketsClose();
	g_World.Close();

	LPCTSTR Reason;
	switch ( g_Serv.m_iExitFlag )
	{
		case -10:	Reason = "Unexpected error occurred";			break;
		case -9:	Reason = "Failed to bind server IP/port";		break;
		case -8:	Reason = "Failed to load worldsave files";		break;
		case -3:	Reason = "Failed to load server settings";		break;
		case -1:	Reason = "Shutdown via commandline";			break;
#ifdef _WIN32
		case 1:		Reason = "X command on console";				break;
#else
		case 1:		Reason = "Terminal closed by SIGHUP signal";	break;
#endif
		case 2:		Reason = "SHUTDOWN command executed";			break;
		case 4:		Reason = "Service shutdown";					break;
		case 5:		Reason = "Console window closed";				break;
		case 6:		Reason = "Proccess aborted by SIGABRT signal";	break;
		default:	Reason = "Server shutdown complete";			break;
	}

	g_Log.Event(LOGM_INIT|LOGL_FATAL, "Server terminated: %s (code %d)\n", Reason, g_Serv.m_iExitFlag);
	g_Log.Close();
}
Beispiel #3
0
void AbstractThread::terminate(bool ended)
{
	if( isActive() )
	{
		bool wasCurrentThread = isCurrentThread();
		if (ended == false)
		{
			g_Log.Event(LOGL_WARN, "Forcing thread '%s' to terminate...\n", getName());

			// if the thread is current then terminating here will prevent cleanup from occurring
			if (wasCurrentThread == false)
			{
#ifdef _WIN32
				TerminateThread(m_handle, 0);
				CloseHandle(m_handle);
#else
				pthread_cancel(m_handle); // IBM say it so
#endif
			}
		}

		// Common things
		ThreadHolder::pop(this);
		m_id = 0;
		m_handle = 0;

		// let everyone know we have been terminated
		m_terminateEvent.set();

		// current thread can be terminated now
		if (ended == false && wasCurrentThread)
		{
#ifdef _WIN32
			_endthreadex(0);
#else
			pthread_exit(0);
#endif
		}
	}
}
Beispiel #4
0
void defragSphere(char *path)
{
	ASSERT(path != NULL);

	CFileText inf;
	CGFile ouf;
	char z[256], z1[256], buf[1024];
	size_t i;
	DWORD uid = UID_CLEAR;
	char *p = NULL, *p1 = NULL;
	DWORD dBytesRead;
	DWORD dTotalMb;
	DWORD mb10 = 10 * 1024 * 1024;
	DWORD mb5 = 5 * 1024 * 1024;
	bool bSpecial;
	DWORD dTotalUIDs;

	char	c,c1,c2;
	DWORD	d;

	// NOTE: Sure I could use CVarDefArray, but it is extremely slow with memory allocation, takes hours
	// to read and save the data. Moreover, it takes less memory in this case and does less convertations.

	g_Log.Event(LOGM_INIT, "Defragmentation (UID alteration) of " SPHERE_TITLE " saves.\n"
		"Use it at your own risk and if you know what you are doing, since it can possibly harm your server.\n"
		"The process can take up to several hours depending on the CPU you have.\n"
		"After finished, you will have your '" SPHERE_FILE "*.scp' save files converted to '" SPHERE_FILE "*.scp.new'.\n");

	DWORD *uids = static_cast<DWORD *>(calloc((SIZE_MAX / 2) / sizeof(DWORD), sizeof(DWORD)));
	for ( i = 0; i < 3; i++ )
	{
		strncpy(z, path, sizeof(z) - 1);
		if ( i == 0 )
			strcat(z, SPHERE_FILE "statics" SPHERE_SCRIPT);
		else if ( i == 1 )
			strcat(z, SPHERE_FILE "world" SPHERE_SCRIPT);
		else
			strcat(z, SPHERE_FILE "chars" SPHERE_SCRIPT);

		g_Log.Event(LOGM_INIT, "Reading %s\n", z);
		if ( !inf.Open(z, OF_READ|OF_TEXT|OF_DEFAULTMODE) )
		{
			g_Log.Event(LOGM_INIT, "Can't open file '%s' for reading. Skipped!\n", z);
			continue;
		}
		dBytesRead = dTotalMb = 0;
		while ( !feof(inf.m_pStream) )
		{
			fgets(buf, sizeof(buf), inf.m_pStream);
			dBytesRead += strlen(buf);
			if ( dBytesRead > mb10 )
			{
				dBytesRead -= mb10;
				dTotalMb += 10;
				g_Log.Event(LOGM_INIT, "Total read %lu Mb\n", dTotalMb);
			}
			if (( buf[0] == 'S' ) && ( strstr(buf, "SERIAL=") == buf ))
			{
				p = buf + 7;
				p1 = p;
				while ( *p1 && ( *p1 != '\r' ) && ( *p1 != '\n' ))
					p1++;
				*p1 = 0;

				//	prepare new uid
				*(p-1) = '0';
				*p = 'x';
				p--;
				uids[uid++] = strtoul(p, &p1, 16);
			}
		}
		inf.Close();
	}

	dTotalUIDs = uid;
	if ( dTotalUIDs <= 0 )
	{
		g_Log.Event(LOGM_INIT, "Save files are empty, defragmentation is not needed\n");
		return;
	}

	g_Log.Event(LOGM_INIT, "Found %lu UIDs (latest: 0%lx)\n", uid, uids[dTotalUIDs - 1]);
	g_Log.Event(LOGM_INIT, "Quick-sorting UIDs array...\n");
	dword_q_sort(uids, 0, dTotalUIDs - 1);

	for ( i = 0; i < 5; i++ )
	{
		strncpy(z, path, sizeof(z) - 1);
		if ( i == 0 )
			strcat(z, SPHERE_FILE "accu.scp");
		else if ( i == 1 )
			strcat(z, SPHERE_FILE "chars" SPHERE_SCRIPT);
		else if ( i == 2 )
			strcat(z, SPHERE_FILE "data" SPHERE_SCRIPT);
		else if ( i == 3 )
			strcat(z, SPHERE_FILE "world" SPHERE_SCRIPT);
		else if ( i == 4 )
			strcat(z, SPHERE_FILE "statics" SPHERE_SCRIPT);

		g_Log.Event(LOGM_INIT, "Updating UIDs in '%s' to '%s.new'\n", z, z);
		if ( !inf.Open(z, OF_READ|OF_TEXT|OF_DEFAULTMODE) )
		{
			g_Log.Event(LOGM_INIT, "Can't open file '%s' for reading. Skipped!\n", z);
			continue;
		}
		strcat(z, ".new");
		if ( !ouf.Open(z, OF_WRITE|OF_CREATE|OF_DEFAULTMODE) )
		{
			g_Log.Event(LOGM_INIT, "Can't open file '%s' for writing. Skipped!\n", z);
			continue;
		}
		dBytesRead = dTotalMb = 0;
		while ( inf.ReadString(buf, sizeof(buf)) )
		{
			uid = strlen(buf);
			if (uid > (COUNTOF(buf) - 3))
				uid = COUNTOF(buf) - 3;

			buf[uid] = buf[uid+1] = buf[uid+2] = 0;	// just to be sure to be in line always
							// NOTE: it is much faster than to use memcpy to clear before reading
			bSpecial = false;
			dBytesRead += uid;
			if ( dBytesRead > mb5 )
			{
				dBytesRead -= mb5;
				dTotalMb += 5;
				g_Log.Event(LOGM_INIT, "Total processed %lu Mb\n", dTotalMb);
			}
			p = buf;

			//	Note 28-Jun-2004
			//	mounts seems having ACTARG1 > 0x30000000. The actual UID is ACTARG1-0x30000000. The
			//	new also should be new+0x30000000. need investigation if this can help making mounts
			//	not to disappear after the defrag
			if (( buf[0] == 'A' ) && ( strstr(buf, "ACTARG1=0") == buf ))		// ACTARG1=
				p += 8;
			else if (( buf[0] == 'C' ) && ( strstr(buf, "CONT=0") == buf ))			// CONT=
				p += 5;
			else if (( buf[0] == 'C' ) && ( strstr(buf, "CHARUID=0") == buf ))		// CHARUID=
				p += 8;
			else if (( buf[0] == 'L' ) && ( strstr(buf, "LASTCHARUID=0") == buf ))	// LASTCHARUID=
				p += 12;
			else if (( buf[0] == 'L' ) && ( strstr(buf, "LINK=0") == buf ))			// LINK=
				p += 5;
			else if (( buf[0] == 'M' ) && ( strstr(buf, "MEMBER=0") == buf ))		// MEMBER=
			{
				p += 7;
				bSpecial = true;
			}
			else if (( buf[0] == 'M' ) && ( strstr(buf, "MORE1=0") == buf ))		// MORE1=
				p += 6;
			else if (( buf[0] == 'M' ) && ( strstr(buf, "MORE2=0") == buf ))		// MORE2=
				p += 6;
			else if (( buf[0] == 'S' ) && ( strstr(buf, "SERIAL=0") == buf ))		// SERIAL=
				p += 7;
			else if ((( buf[0] == 'T' ) && ( strstr(buf, "TAG.") == buf )) ||		// TAG.=
					 (( buf[0] == 'R' ) && ( strstr(buf, "REGION.TAG") == buf )))
			{
				while ( *p && ( *p != '=' )) p++;
				p++;
			}
			else if (( i == 2 ) && strchr(buf, '='))	// spheredata.scp - plain VARs
			{
				while ( *p && ( *p != '=' )) p++;
				p++;
			}
			else p = NULL;

			//	UIDs are always hex, so prefixed by 0
			if ( p && ( *p != '0' )) p = NULL;

			//	here we got potentialy UID-contained variable
			//	check if it really is only UID-like var containing
			if ( p )
			{
				p1 = p;
				while ( *p1 &&
					((( *p1 >= '0' ) && ( *p1 <= '9' )) ||
					 (( *p1 >= 'a' ) && ( *p1 <= 'f' )))) p1++;
				if ( !bSpecial )
				{
					if ( *p1 && ( *p1 != '\r' ) && ( *p1 != '\n' )) // some more text in line
						p = NULL;
				}
			}

			//	here we definitely know that this is very uid-like
			if ( p )
			{
				c = *p1;

				*p1 = 0;
				//	here in p we have the current value of the line.
				//	check if it is a valid UID

				//	prepare converting 0.. to 0x..
				c1 = *(p-1);
				c2 = *p;
				*(p-1) = '0';
				*p = 'x';
				p--;
				uid = strtoul(p, &p1, 16);
				p++;
				*(p-1) = c1;
				*p = c2;
				//	Note 28-Jun-2004
				//	The search algourytm is very simple and fast. But maybe integrate some other, at least /2 algorythm
				//	since has amount/2 tryes at worst chance to get the item and never scans the whole array
				//	It should improve speed since defragmenting 150Mb saves takes ~2:30 on 2.0Mhz CPU
				{
					DWORD	dStep = dTotalUIDs/2;
					d = dStep;
					for (;;)
					{
						dStep /= 2;

						if ( uids[d] == uid )
						{
							uid = d | (uids[d]&0xF0000000);	// do not forget attach item and special flags like 04..
							break;
						}
						else if ( uids[d] < uid ) d += dStep;
						else d -= dStep;

						if ( dStep == 1 )
						{
							uid = ULONG_MAX;
							break; // did not find the UID
						}
					}
				}

				//	Search for this uid in the table
/*				for ( d = 0; d < dTotalUIDs; d++ )
				{
					if ( !uids[d] )	// end of array
					{
						uid = ULONG_MAX;
						break;
					}
					else if ( uids[d] == uid )
					{
						uid = d | (uids[d]&0xF0000000);	// do not forget attach item and special flags like 04..
						break;
					}
				}*/

				//	replace UID by the new one since it has been found
				*p1 = c;
				if ( uid != ULONG_MAX )
				{
					*p = 0;
					strncpy(z, p1, sizeof(z) - 1);
					sprintf(z1, "0%lx", uid);
					strcat(buf, z1);
					strcat(buf, z);
				}
			}
			//	output the resulting line
			ouf.Write(buf, strlen(buf));
		}
		inf.Close();
		ouf.Close();
	}
	free(uids);
	g_Log.Event(LOGM_INIT,	"Defragmentation complete.\n");
}
Beispiel #5
0
int Sphere_InitServer( int argc, char *argv[] )
{
#ifdef EXCEPTIONS_DEBUG
	const char *m_sClassName = "Sphere";
#endif
	EXC_TRY("Init");
	ASSERT(MAX_BUFFER >= sizeof(CEvent));
	ASSERT(sizeof(int) == sizeof(DWORD));	// make this assumption often.
	ASSERT(sizeof(ITEMID_TYPE) == sizeof(DWORD));
	ASSERT(sizeof(WORD) == 2 );
	ASSERT(sizeof(DWORD) == 4 );
	ASSERT(sizeof(NWORD) == 2 );
	ASSERT(sizeof(NDWORD) == 4 );
	ASSERT(sizeof(CUOItemTypeRec) == 37 ); // byte pack working ?
	ASSERT((std::numeric_limits<size_t>::min)() == 0); // ensure unsigned

#ifdef _WIN32
	if ( !QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&llTimeProfileFrequency)) )
		llTimeProfileFrequency = 1000;

	#if !defined(_DEBUG) && !defined(__MINGW32__)
		EXC_SET("setting exception catcher");
		SetExceptionTranslator();
	#endif
#endif

	EXC_SET("loading");
	if ( !g_Serv.Load() )
		return -3;

	if ( argc > 1 )
	{
		EXC_SET("cmdline");
		if ( !g_Serv.CommandLine(argc, argv) )
			return -1;
	}

	WritePidFile(2);

	EXC_SET("load world");
	if ( !g_World.LoadAll() )
		return -8;

	EXC_SET("sockets init");
	if ( !g_Serv.SocketsInit() )
		return -9;

	//	load auto-complete dictionary
	EXC_SET("auto-complete");
	{
		CFileText	dict;
		if ( dict.Open(SPHERE_FILE ".dic", OF_READ|OF_TEXT|OF_DEFAULTMODE) )
		{
			TCHAR * pszTemp = Str_GetTemp();
			size_t count = 0;
			while ( !dict.IsEOF() )
			{
				dict.ReadString(pszTemp, SCRIPT_MAX_LINE_LEN-1);
				if ( *pszTemp )
				{
					TCHAR *c = strchr(pszTemp, '\r');
					if ( c != NULL )
						*c = '\0';

					c = strchr(pszTemp, '\n');
					if ( c != NULL )
						*c = '\0';

					if ( *pszTemp != '\0' )
					{
						count++;
						g_AutoComplete.AddTail(pszTemp);
					}
				}
			}
			g_Log.Event(LOGM_INIT, "Auto-complete dictionary loaded (contains %" FMTSIZE_T " words)\n", count);
			dict.Close();
		}
	}

	EXC_SET("finalizing");
	g_Serv.SetServerMode(SERVMODE_Run);
	g_Log.Event(LOGM_INIT, "Startup complete (Items=%lu, Chars=%lu, Accounts=%lu)\nPress '?' for console commands\n\n", g_Serv.StatGet(SERV_STAT_ITEMS), g_Serv.StatGet(SERV_STAT_CHARS), g_Serv.StatGet(SERV_STAT_ACCOUNTS));

	if ( !g_Accounts.Account_GetCount() )
		g_Log.Event(LOGL_WARN|LOGM_INIT, "The server has no accounts. To create admin account you must type:\n  ACCOUNT ADD [login] [password]\n  ACCOUNT [login] PLEVEL 7\n");

	// Trigger server start
	g_Serv.r_Call("f_onserver_start", &g_Serv, NULL);
	return g_Serv.m_iExitFlag;

	EXC_CATCH;

	EXC_DEBUG_START;
	g_Log.EventDebug("cmdline argc=%d starting with %p (argv1='%s')\n", argc, static_cast<void *>(argv), ( argc > 2 ) ? argv[1] : "");
	EXC_DEBUG_END;
	return -10;
}
Beispiel #6
0
int Sphere_InitServer( int argc, char *argv[] )
{
	const char *m_sClassName = "Sphere";
	EXC_TRY("Init");
	ASSERT(MAX_BUFFER >= sizeof(CCommand));
	ASSERT(MAX_BUFFER >= sizeof(CEvent));
	ASSERT(sizeof(int) == sizeof(DWORD));	// make this assumption often.
	ASSERT(sizeof(ITEMID_TYPE) == sizeof(DWORD));
	ASSERT(sizeof(WORD) == 2 );
	ASSERT(sizeof(DWORD) == 4 );
	ASSERT(sizeof(NWORD) == 2 );
	ASSERT(sizeof(NDWORD) == 4 );
	ASSERT(sizeof(CUOItemTypeRec) == 37 ); // byte pack working ?
	ASSERT((std::numeric_limits<size_t>::min)() == 0); // ensure unsigned

#ifdef _WIN32
	if ( !QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&llTimeProfileFrequency)))
		llTimeProfileFrequency = 1000;

	EXC_SET("setting exception catcher");
	SetExceptionTranslator();
#endif // _WIN32

	EXC_SET("loading");
	if ( !g_Serv.Load() )
		return -3;

	if ( argc > 1 )
	{
		EXC_SET("cmdline");
		if ( !g_Serv.CommandLine(argc, argv) )
			return -1;
	}

	WritePidFile(2);

	EXC_SET("sockets init");
	if ( !g_Serv.SocketsInit() )
		return -9;
	EXC_SET("load world");
	if ( !g_World.LoadAll() )
		return -8;

	//	load auto-complete dictionary
	EXC_SET("auto-complete");
	{
		CFileText	dict;
		if ( dict.Open(GRAY_FILE ".dic", OF_READ|OF_TEXT|OF_DEFAULTMODE) )
		{
			TCHAR * pszTemp = Str_GetTemp();
			size_t count = 0;
			while ( !dict.IsEOF() )
			{
				dict.ReadString(pszTemp, SCRIPT_MAX_LINE_LEN-1);
				if ( *pszTemp )
				{
					TCHAR *c = strchr(pszTemp, '\r');
					if ( c != NULL )
						*c = '\0';

					c = strchr(pszTemp, '\n');
					if ( c != NULL )
						*c = '\0';

					if ( *pszTemp != '\0' )
					{
						count++;
						g_AutoComplete.AddTail(pszTemp);
					}
				}
			}
			g_Log.Event(LOGM_INIT, "Auto-complete dictionary loaded (contains %" FMTSIZE_T " words).\n", count);
			dict.Close();
		}
	}
	g_Serv.SetServerMode(SERVMODE_Run);	// ready to go.

	// Display EF/OF Flags
	g_Cfg.PrintEFOFFlags();

	EXC_SET("finilizing");
	g_Log.Event(LOGM_INIT, "%s", g_Serv.GetStatusString(0x24));
	g_Log.Event(LOGM_INIT, "Startup complete. items=%lu, chars=%lu\n", g_Serv.StatGet(SERV_STAT_ITEMS), g_Serv.StatGet(SERV_STAT_CHARS));

#ifdef _WIN32
	g_Log.Event(LOGM_INIT, "Press '?' for console commands\n");
#endif

	// Trigger server start
	g_Serv.r_Call("f_onserver_start", &g_Serv, NULL);
	return 0;

	EXC_CATCH;

	EXC_DEBUG_START;
	g_Log.EventDebug("cmdline argc=%d starting with %p (argv1='%s')\n", argc, static_cast<void *>(argv), ( argc > 2 ) ? argv[1] : "");
	EXC_DEBUG_END;
	return -10;
}
Beispiel #7
0
void AbstractThread::run()
{
	// is the very first since there is a possibility of something being altered there
	onStart();

	int exceptions = 0;
	bool lastWasException = false;
	m_terminateRequested = false;

	for (;;)
	{
		bool gotException = false;

		//	report me being alive if I am being checked for status
		if( m_hangCheck != 0 )
		{
			m_hangCheck = 0;
		}

		try
		{
			tick();

			// ensure this is recorded as 'idle' time (ideally this should
			// be in tick() but we cannot guarantee it to be called there
			CurrentProfileData.Start(PROFILE_IDLE);
		}
		catch( const CException& e )
		{
			gotException = true;
			g_Log.CatchEvent(&e, "%s::tick", getName());
			CurrentProfileData.Count(PROFILE_STAT_FAULTS, 1);
		}
		catch( ... )
		{
			gotException = true;
			g_Log.CatchEvent(NULL, "%s::tick", getName());
			CurrentProfileData.Count(PROFILE_STAT_FAULTS, 1);
		}

		if( gotException )
		{
			if( lastWasException )
			{
				exceptions++;
			}
			else
			{
				lastWasException = true;
				exceptions = 0;
			}
			if( exceptions >= EXCEPTIONS_ALLOWED )
			{
				// a bad thing really happened. ALL previous EXCEPTIONS_ALLOWED ticks resulted in exception
				// almost for sure we have looped somewhere and have no way to get out from this situation
				// probably a thread restart can fix the problems
				// but there is no real need to restart a thread, we will just simulate a thread restart,
				// notifying a subclass like we have been just restarted, so it will restart it's operations
				g_Log.Event(LOGL_CRIT, "'%s' thread raised too many exceptions, restarting...\n", getName());
				onStart();
				lastWasException = false;
			}
		}
		else
		{
			lastWasException = false;
		}

		if( shouldExit() )
			break;

		m_sleepEvent.wait(m_tickPeriod);
	}
}