2
3
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-14 02:27:40 -04:00

Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin

This commit is contained in:
JWPlatt
2011-03-12 12:34:52 -05:00
commit a20a222fc2
3976 changed files with 1301356 additions and 0 deletions

View File

@ -0,0 +1,381 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/NucleusLib/pnIniExe/Private/Win32/pnW32IniChange.cpp
*
***/
#include "../../Pch.h"
#pragma hdrstop
#ifdef HS_BUILD_FOR_WIN32
/*****************************************************************************
*
* Private
*
***/
struct IniChangeFile;
struct IniChangeReg {
LINK(IniChangeReg) fLink;
FIniFileChangeCallback fNotify;
qword fLastWriteTime;
wchar fFileName[MAX_PATH];
};
static CLock s_lock;
static HANDLE s_event;
static HANDLE s_signal;
static HANDLE s_thread;
static HANDLE s_change;
static bool s_running;
static IniChangeReg * s_dispatch;
static wchar s_directory[MAX_PATH];
static LISTDECL(IniChangeReg, fLink) s_callbacks;
/****************************************************************************
*
* Change notification
*
***/
//===========================================================================
static qword GetFileTimestamp (const wchar fileName[]) {
HANDLE find;
WIN32_FIND_DATAW fd;
qword lastWriteTime;
if (INVALID_HANDLE_VALUE != (find = FindFirstFileW(fileName, &fd))) {
COMPILER_ASSERT(sizeof(lastWriteTime) == sizeof(fd.ftLastWriteTime));
lastWriteTime = * (const qword *) &fd.ftLastWriteTime;
FindClose(find);
}
else {
lastWriteTime = 1; // any non-zero, non-valid number
}
return lastWriteTime;
}
//===========================================================================
static void ChangeDispatch_WL (IniChangeReg * marker) {
while (nil != (s_dispatch = s_callbacks.Next(marker))) {
// Move the marker to the next location
s_callbacks.Link(marker, kListLinkAfter, s_dispatch);
// If the file record time matches the file data time
// then there's no need to reprocess the callbacks
qword lastWriteTime = GetFileTimestamp(s_dispatch->fFileName);
if (s_dispatch->fLastWriteTime == lastWriteTime)
continue;
s_dispatch->fLastWriteTime = lastWriteTime;
// Leave lock to perform callback
s_lock.LeaveWrite();
s_dispatch->fNotify(s_dispatch->fFileName);
s_lock.EnterWrite();
}
// List traversal complete
SetEvent(s_signal);
}
//===========================================================================
static unsigned THREADCALL IniSrvThreadProc (AsyncThread * thread) {
ref(thread);
IniChangeReg marker;
marker.fNotify = nil;
s_lock.EnterWrite();
s_callbacks.Link(&marker, kListHead);
s_lock.LeaveWrite();
HANDLE handles[2];
handles[0] = s_change;
handles[1] = s_event;
unsigned sleepMs = INFINITE;
for (;;) {
// Wait until something happens
unsigned result = WaitForMultipleObjects(
arrsize(handles),
handles,
false,
sleepMs
);
if (!s_running)
break;
// reset the sleep time
sleepMs = INFINITE;
if (result == WAIT_OBJECT_0) {
if (!FindNextChangeNotification(s_change)) {
LogMsg(
kLogError,
"IniSrv: FindNextChangeNotification() failed %#x",
GetLastError()
);
break;
}
// a change notification occurs when a file is created, even
// though it may take a number of seconds before the file data
// has been copied. Wait a few seconds after the last change
// notification so that files have a chance to stabilize.
sleepMs = 5 * 1000;
// When the timeout occurs, reprocess the entire list
s_lock.EnterWrite();
s_callbacks.Link(&marker, kListHead);
s_lock.LeaveWrite();
}
else if ((result == WAIT_OBJECT_0 + 1) || (result == WAIT_TIMEOUT)) {
// Queue for deadlock check
#ifdef SERVER
void * check = CrashAddDeadlockCheck(thread->handle, L"plW32IniChange.NtWorkerThreadProc");
#endif
s_lock.EnterWrite();
ChangeDispatch_WL(&marker);
s_lock.LeaveWrite();
// Unqueue for deadlock check
#ifdef SERVER
CrashRemoveDeadlockCheck(check);
#endif
}
else {
LogMsg(
kLogError,
"IniChange: WaitForMultipleObjects failed %#x",
GetLastError()
);
break;
}
}
// Cleanup
s_lock.EnterWrite();
s_callbacks.Unlink(&marker);
s_lock.LeaveWrite();
return 0;
}
/****************************************************************************
*
* Exports
*
***/
//===========================================================================
void IniChangeInitialize (const wchar dir[]) {
ASSERT(!s_running);
s_running = true;
const char * function;
for (;;) {
// Create the config directory
PathGetProgramDirectory(s_directory, arrsize(s_directory));
PathAddFilename(s_directory, s_directory, dir, arrsize(s_directory));
if (EPathCreateDirError error = PathCreateDirectory(s_directory, 0))
LogMsg(kLogError, "IniChange: CreateDir failed %u", error);
// Open change notification for directory
s_change = FindFirstChangeNotificationW(
s_directory,
false, // watchSubTree = false
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME
);
if (!s_change) {
function = "FindFirstChangeNotification";
break;
}
// create thread event
s_event = CreateEvent(
(LPSECURITY_ATTRIBUTES) 0,
false, // auto-reset
false, // initial state off
(LPCTSTR) 0 // name
);
if (!s_event) {
function = "CreateEvent";
break;
}
// create signal event
s_signal = CreateEvent(
(LPSECURITY_ATTRIBUTES) 0,
true, // manual-reset
false, // initial state off
(LPCTSTR) 0 // name
);
if (!s_signal) {
function = "CreateEvent";
break;
}
// create thread
s_thread = (HANDLE) AsyncThreadCreate(
IniSrvThreadProc,
nil,
L"IniSrvChange"
);
if (!s_thread) {
function = "AsyncThreadCreate";
break;
}
// Success!
return;
}
// Failure!
LogMsg(
kLogError,
"IniChange: %s failed (%#x)",
function,
GetLastError()
);
}
//===========================================================================
void IniChangeDestroy () {
s_running = false;
if (s_thread) {
SetEvent(s_event);
WaitForSingleObject(s_thread, INFINITE);
CloseHandle(s_thread);
s_thread = nil;
}
if (s_event) {
CloseHandle(s_event);
s_event = nil;
}
if (s_signal) {
CloseHandle(s_signal);
s_signal = nil;
}
if (s_change) {
FindCloseChangeNotification(s_change);
s_change = nil;
}
ASSERT(!s_callbacks.Head());
}
//===========================================================================
void IniChangeAdd (
const wchar fileName[],
FIniFileChangeCallback callback,
IniChangeReg ** changePtr
) {
ASSERT(fileName);
ASSERT(callback);
ASSERT(changePtr);
ASSERT(s_running);
// Create a callback record
IniChangeReg * change = NEW(IniChangeReg);
change->fNotify = callback;
change->fLastWriteTime = 0;
PathAddFilename(
change->fFileName,
s_directory,
fileName,
arrsize(change->fFileName)
);
PathRemoveExtension(change->fFileName, change->fFileName, arrsize(change->fFileName));
PathAddExtension(change->fFileName, change->fFileName, L".ini", arrsize(change->fFileName));
// Set result before callback to avoid race condition
*changePtr = change;
// Signal change record for immediate callback
// and wait for callback completion
IniChangeSignal(change, true);
}
//===========================================================================
void IniChangeRemove (
IniChangeReg * change,
bool wait
) {
ASSERT(change);
s_lock.EnterWrite();
{
// Wait until the callback is no longer being dispatched
if (wait) {
while (s_dispatch == change) {
s_lock.LeaveWrite();
AsyncSleep(10);
s_lock.EnterWrite();
}
}
// Remove change object from list so that
// it can be deleted outside the lock
change->fLink.Unlink();
}
s_lock.LeaveWrite();
// Delete object outside critical section
DEL(change);
}
//===========================================================================
void IniChangeSignal (
IniChangeReg * change,
bool wait
) {
ASSERT(change);
s_lock.EnterWrite();
{
s_callbacks.Link(change, kListTail);
change->fLastWriteTime = 0;
ResetEvent(s_signal);
}
s_lock.LeaveWrite();
// Wake up the change thread to process this request
SetEvent(s_event);
// Wait until the request has been processed
if (wait)
WaitForSingleObject(s_signal, INFINITE);
}
#endif // HS_BUILD_FOR_WIN32

View File

@ -0,0 +1,202 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/NucleusLib/pnIniExe/Private/pnIniSrv.cpp
*
***/
#include "../Pch.h"
#pragma hdrstop
#ifdef SERVER
/*****************************************************************************
*
* Internal
*
***/
const unsigned CLASS_C_SUBNET_MASK = 0xFFFFFF00;
const NetAddressNode LOOPBACK_ADDRESS_NODE = 0x7F000001;
//============================================================================
struct PrivilegedAddressBlock : THashKeyVal<unsigned> {
HASHLINK(PrivilegedAddressBlock) link;
NetAddressNode startAddress;
NetAddressNode endAddress;
EServerRights serverRights;
};
//============================================================================
#define ADDRESS_BLOCK_TABLE HASHTABLEDECL(PrivilegedAddressBlock, THashKeyVal<unsigned>, link)
static CCritSect s_critsect;
static ADDRESS_BLOCK_TABLE s_addressBlocks;
//============================================================================
static void SrvRightsDestroy () {
s_critsect.Enter();
{
s_addressBlocks.Clear();
}
s_critsect.Leave();
}
//============================================================================
AUTO_INIT_FUNC(InitSrvRightsIni) {
atexit(SrvRightsDestroy);
}
//============================================================================
static EServerRights GetServerRightsFromString(const wchar string[]) {
if (StrCmpI(string, L"Server") == 0)
return kSrvRightsServer;
else if (StrCmpI(string, L"Basic") == 0)
return kSrvRightsBasic;
else
return kSrvRightsNone;
}
static void IAddAddressBlock(ADDRESS_BLOCK_TABLE & addrList, NetAddressNode startAddr, NetAddressNode endAddr, EServerRights srvRights) {
PrivilegedAddressBlock* addrBlock = NEW(PrivilegedAddressBlock);
addrBlock->startAddress = startAddr;
addrBlock->serverRights = srvRights;
if (endAddr == 0)
addrBlock->endAddress = addrBlock->startAddress;
else
addrBlock->endAddress = endAddr;
if ( (addrBlock->startAddress & CLASS_C_SUBNET_MASK) != (addrBlock->endAddress & CLASS_C_SUBNET_MASK) ) {
LogMsg(kLogDebug, L"IniSrv: Error creating privileged address block - start address and end address aren't from the same subnet.");
DEL(addrBlock);
}
else {
addrBlock->SetValue(startAddr & CLASS_C_SUBNET_MASK);
addrList.Add(addrBlock);
}
}
/*****************************************************************************
*
* Exports
*
***/
//============================================================================
EServerRights SrvIniGetServerRightsByNode (NetAddressNode addrNode) {
EServerRights retVal = kSrvRightsBasic;
unsigned addrSubNet = (addrNode & CLASS_C_SUBNET_MASK);
s_critsect.Enter();
{
PrivilegedAddressBlock* addrBlock = s_addressBlocks.Find(addrSubNet);
while (addrBlock) {
if (addrBlock->startAddress <= addrNode && addrNode <= addrBlock->endAddress) {
retVal = addrBlock->serverRights;
break;
}
addrBlock = s_addressBlocks.FindNext(addrSubNet, addrBlock);
}
}
s_critsect.Leave();
return retVal;
}
//============================================================================
EServerRights SrvIniGetServerRights (const NetAddress & addr) {
NetAddressNode addrNode = NetAddressGetNode(addr);
return SrvIniGetServerRightsByNode(addrNode);
}
//============================================================================
void SrvIniParseServerRights (Ini * ini) {
unsigned iter;
const IniValue *value;
ADDRESS_BLOCK_TABLE newaddresstable;
ADDRESS_BLOCK_TABLE removeaddresstable;
value = IniGetFirstValue(
ini,
L"Privileged Addresses",
L"Addr",
&iter
);
// add ini file address blocks
while (value) {
wchar valStr[20];
NetAddressNode start;
NetAddressNode end;
EServerRights rights;
IniGetString(value, valStr, arrsize(valStr), 0);
start = NetAddressNodeFromString(valStr, nil);
IniGetString(value, valStr, arrsize(valStr), 1);
end = NetAddressNodeFromString(valStr, nil);
IniGetString(value, valStr, arrsize(valStr), 2);
rights = GetServerRightsFromString(valStr);
IAddAddressBlock(newaddresstable, start, end, rights);
value = IniGetNextValue(value, &iter);
}
// Add local addresses and loopback
NetAddressNode nodes[16];
unsigned count = NetAddressGetLocal(arrsize(nodes), nodes);
for (unsigned i = 0; i < count; ++i) {
IAddAddressBlock(newaddresstable, nodes[i], nodes[i], kSrvRightsServer);
}
IAddAddressBlock(newaddresstable, LOOPBACK_ADDRESS_NODE, LOOPBACK_ADDRESS_NODE, kSrvRightsServer);
s_critsect.Enter();
{
while (PrivilegedAddressBlock* addrBlock = s_addressBlocks.Head())
removeaddresstable.Add(addrBlock);
while (PrivilegedAddressBlock* addrBlock = newaddresstable.Head())
s_addressBlocks.Add(addrBlock);
}
s_critsect.Leave();
removeaddresstable.Clear();
}
#endif