1
0
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-18 11:19:10 +00: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 b970ae4bad
3976 changed files with 1301355 additions and 0 deletions

View File

@ -0,0 +1,67 @@
/*==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/pnNetLog/Intern.h
*
***/
#ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNNETLOG_INTERN_H
#error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnNetLog/Intern.h included more than once"
#endif
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNNETLOG_INTERN_H
/*****************************************************************************
*
* pnNlApi.cpp
*
***/
const NetLogEvent *NetLogFindEvent (unsigned type, ESrvType srvType);
/*****************************************************************************
*
* pnNlCli.cpp
*
***/
void NetLogCliInitialize (ESrvType srvType);
void NetLogCliShutdown ();
void NetLogCliDestroy ();
void NetLogCliSendEvent (const NetLogEvent &event, va_list args);
/*****************************************************************************
*
* pnNlSrv.cpp
*
***/
void NetLogSrvInitialize ();
void NetLogSrvShutdown ();
void NetLogSrvDestroy ();

View File

@ -0,0 +1,58 @@
/*==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/pnNetLog/Pch.h
*
***/
#ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNNETLOG_PCH_H
#error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnNetLog/Pch.h included more than once"
#endif
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNNETLOG_PCH_H
// NucleusLib
#include "pnUtils/pnUtils.h"
#include "pnNetBase/pnNetBase.h"
#include "pnAsyncCore/pnAsyncCore.h"
#include "pnNetCli/pnNetCli.h"
#ifdef SERVER
#include "pnIni/pnIni.h"
#include "../ServerLib/psUtils/psUtils.h"
#endif
#define USES_PROTOCOL_SRV2LOG
#include "pnNetProtocol/pnNetProtocol.h"
#include "pnProduct/pnProduct.h"
// Local
#include "pnNetLog.h"
#include "Intern.h"
// System
#include <malloc.h> // _alloca

View File

@ -0,0 +1,148 @@
/*==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/pnNetLog/pnNetLog.h
*
***/
#ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNNETLOG_PNNETLOG_H
#error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnNetLog/pnNetLog.h included more than once"
#endif
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNNETLOG_PNNETLOG_H
#define MAX_NAME_LEN 64
/*****************************************************************************
*
*
Look at psLogEvents/psLeAuth for an example of how to create a new LogEvent
*
***/
/*****************************************************************************
*
* Log Template Definitions
*
***/
enum ELogParamType {
kLogParamInt, // (int)
kLogParamUnsigned, // (unsigned)
kLogParamFloat, // (float)
kLogParamUuid, // Uuid
kLogParamStringW, // (const wchar *)
kLogParamLong, // (long) or (dword)
kLogParamLongLong, // (long long) or (qword)
kNumLogParamTypes
};
struct NetLogField {
ELogParamType type; // element type
wchar name[MAX_PATH];
};
struct NetLogEvent {
ESrvType srvType;
unsigned logEventType;
const wchar * eventName;
const NetLogField * fields;
unsigned numFields;
};
struct NetLogSrvField {
const wchar *name;
const wchar *data;
};
#define NET_LOG_FIELD_INT(name) { kLogParamInt, name }
#define NET_LOG_FIELD_UNSIGNED(name) { kLogParamUnsigned, name }
#define NET_LOG_FIELD_FLOAT(name) { kLogParamFloat, name }
#define NET_LOG_FIELD_STRING(name) { kLogParamStringW, name }
#define NET_LOG_FIELD_UUID(name) { kLogParamUuid, name }
#define NET_LOG_FIELD_LONG(name) { kLogParamLong, name }
#define NET_LOG_FIELD_LONGLONG(name) { kLogParamLongLong, name }
#define NET_LOG_EVENT_AUTH(name) { kSrvTypeAuth, kLogEventId_##name, L#name, kLogEventFields_##name, arrsize( kLogEventFields_##name )}
#define NET_LOG_EVENT_GAME(name) { kSrvTypeGame, kLogEventId_##name, L#name, kLogEventFields_##name, arrsize( kLogEventFields_##name )}
#define NET_LOG_EVENT_MCP(name) { kSrvTypeMcp, kLogEventId_##name, L#name, kLogEventFields_##name, arrsize( kLogEventFields_##name )}
#define NET_LOG_EVENT_DB(name) { kSrvTypeDb, kLogEventId_##name, L#name, kLogEventFields_##name, arrsize( kLogEventFields_##name )}
/*****************************************************************************
*
* pnNlApi.cpp
*
***/
void NetLogInitialize (ESrvType srvType);
void NetLogShutdown ();
void NetLogDestroy ();
void NetLogRegisterEvents (const NetLogEvent events[], unsigned count);
// Should only be called by psLogEvents - look there for logging functions
void NetLogSendEvent (
unsigned type,
...
);
/*****************************************************************************
*
* pnNlConn.cpp
*
***/
enum {
kNlCliNumConn,
kNlCliNumTrans,
kNlCliNumPendingSaves,
kNlCliNumPerf,
};
long NlCliGetPerf (unsigned index);
/*****************************************************************************
*
* pnNlSrv.cpp
*
***/
struct LogConn;
enum {
kNlSrvPerfConnCount,
kNlSrvPerfConnDenied,
kNlSrvNumPerf
};
typedef void (*NlSrvCallback)(const NetLogEvent *event, const ARRAY(wchar) &, unsigned, NetAddressNode &, qword, unsigned, unsigned);
long NetLogSrvGetPerf (unsigned index);
void NetLogSrvRegisterCallback(NlSrvCallback callback);
void LogConnIncRef (LogConn * conn);
void LogConnDecRef (LogConn * conn);

View File

@ -0,0 +1,215 @@
/*==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/pnNetLog/pnNlApi.cpp
*
***/
#include "Pch.h"
#pragma hdrstop
/*****************************************************************************
*
* Private Data
*
***/
struct EventHash {
unsigned eventType;
ESrvType srvType;
inline EventHash (
unsigned eventType,
ESrvType srvType
);
inline dword GetHash () const;
inline bool operator== (const EventHash & rhs) const;
};
struct NetLogEventHash : EventHash {
const NetLogEvent * event;
NetLogEventHash(
unsigned eventType,
ESrvType srvType,
const NetLogEvent *event
);
HASHLINK(NetLogEventHash) link;
};
static CCritSect s_critsect;
static ESrvType s_srvType;
static HASHTABLEDECL(NetLogEventHash, EventHash, link) s_registeredEvents;
/*****************************************************************************
*
* NetLogEventHash
*
***/
//============================================================================
NetLogEventHash::NetLogEventHash (
unsigned eventType,
ESrvType srvType,
const NetLogEvent *event
) : EventHash(eventType, srvType),
event(event)
{
}
/*****************************************************************************
*
* Event Hash
*
***/
//============================================================================
inline EventHash::EventHash (
unsigned eventType,
ESrvType srvType
) : eventType(eventType)
, srvType(srvType)
{
}
//============================================================================
inline dword EventHash::GetHash () const {
CHashValue hash(this, sizeof(*this));
return hash.GetHash();
}
//============================================================================
inline bool EventHash::operator== (const EventHash & rhs) const {
return
eventType == rhs.eventType &&
srvType == rhs.srvType;
}
/*****************************************************************************
*
* Private Functions
*
***/
//============================================================================
static void NetLogUnRegisterEvents () {
HASHTABLEDECL(NetLogEventHash, EventHash, link) tempHashTable;
s_critsect.Enter();
{
while(NetLogEventHash *hash = s_registeredEvents.Head()) {
tempHashTable.Add(hash);
}
}
s_critsect.Leave();
while(NetLogEventHash *hash = tempHashTable.Head()) {
delete hash;
}
}
/*****************************************************************************
*
* Public Functions
*
***/
//============================================================================
void NetLogInitialize (ESrvType srvType) {
s_srvType = srvType;
if(s_srvType == kSrvTypeLog)
NetLogSrvInitialize();
else
NetLogCliInitialize(srvType);
}
//============================================================================
void NetLogShutdown () {
if(s_srvType == kSrvTypeLog)
NetLogSrvShutdown();
else
NetLogCliShutdown();
NetLogUnRegisterEvents();
}
//============================================================================
void NetLogDestroy () {
if(s_srvType == kSrvTypeLog)
NetLogSrvDestroy();
else
NetLogCliDestroy();
}
//============================================================================
void NetLogRegisterEvents (const NetLogEvent events[], unsigned count) {
NetLogEventHash *hash;
HASHTABLEDECL(NetLogEventHash, EventHash, link) tempHashTable;
for(unsigned i = 0; i < count; ++i) {
hash = NEW(NetLogEventHash)(events[i].logEventType, events[i].srvType, &events[i]);
tempHashTable.Add(hash);
}
s_critsect.Enter();
{
while(NetLogEventHash *hash = tempHashTable.Head()) {
s_registeredEvents.Add(hash);
}
}
s_critsect.Leave();
}
//============================================================================
const NetLogEvent *NetLogFindEvent (unsigned type, ESrvType srvType) {
NetLogEventHash *hash;
s_critsect.Enter();
{
hash = s_registeredEvents.Find(EventHash(type, srvType));
}
s_critsect.Leave();
return hash ? hash->event : nil;
}
//============================================================================
void NetLogSendEvent (
unsigned type
...
) {
const NetLogEvent *event = NetLogFindEvent(type, s_srvType);
if(event) {
va_list args;
va_start(args, type);
NetLogCliSendEvent(*event, args);
va_end(args);
}
else {
LogMsg( kLogError, "unable to log event, event not found SrvType: %d EventType: %d.", s_srvType, type);
}
}

View File

@ -0,0 +1,542 @@
/*==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/pnNetLog/pnNlCli.cpp
*
***/
#include "Pch.h"
#pragma hdrstop
/*****************************************************************************
*
* Private
*
***/
struct NetLogConn : SrvConn {
NetAddress netaddr;
ESrvType srvType;
NetLogConn (const NetAddress & addr, ESrvType srvType);
~NetLogConn ();
void Connect (
AsyncCancelId * cancelId,
FAsyncNotifySocketProc notifyProc,
void * param
);
};
struct LogMsgTrans : SrvTrans {
Srv2Log_LogMsg *msgBuffer;
LogMsgTrans();
~LogMsgTrans();
bool OnTransReply (
ENetError * error,
SrvMsgHeader * msg
);
};
struct LogConnEventNode {
LINK(LogConnEventNode) link;
Srv2Log_LogMsg * msg;
unsigned sendTimeMs;
LogConnEventNode(Srv2Log_LogMsg *msg, unsigned timeStampMs);
};
/*****************************************************************************
*
* Private Data
*
***/
static NetLogConn * s_conn;
static CCritSect s_critsect;
static IniChangeReg * s_change;
static ESrvType s_srvType;
static LISTDECL(LogConnEventNode, link) s_eventQueue;
static AsyncTimer * s_timer;
static long s_perf[kNlCliNumPerf];
static bool s_running;
static const unsigned kIssueSaveMs = 100;
static const unsigned kMaxNumberOfTransactions = 2000;
/*****************************************************************************
*
* Private Functions
*
***/
//============================================================================
static NetLogConn * GetConnIncRef () {
NetLogConn * conn;
s_critsect.Enter();
{
if (nil != (conn = s_conn))
conn->IncRef();
}
s_critsect.Leave();
return conn;
}
//============================================================================
static void NetLogConnConnect (NetAddress & addr, ESrvType srvType) {
NetLogConn *conn = SRV_CONN_ALLOC(NetLogConn)(addr, srvType);
s_critsect.Enter();
{
SWAP(s_conn, conn);
}
s_critsect.Leave();
if (conn)
conn->Destroy();
}
//============================================================================
static void NetLogConnDisconnect () {
NetLogConn *conn = nil;
s_critsect.Enter();
{
SWAP(s_conn, conn);
}
s_critsect.Leave();
if (conn)
conn->Destroy();
}
//============================================================================
static void AddEventNode (Srv2Log_LogMsg *msg) {
LogConnEventNode *node = NEW(LogConnEventNode)(msg, TimeGetMs() + kIssueSaveMs);
s_critsect.Enter();
{
s_eventQueue.Link(node);
}
s_critsect.Leave();
AsyncTimerUpdate(
s_timer,
kIssueSaveMs,
kAsyncTimerUpdateSetPriorityHigher
);
}
//============================================================================
static void ParseIni (Ini * ini) {
unsigned iter;
const IniValue * value = IniGetFirstValue(
ini,
L"Server Locations",
L"LogSrv",
&iter
);
if (value) {
wchar addrStr[32];
IniGetString(value, addrStr, arrsize(addrStr), 0, nil);
NetAddress addr;
NetAddressFromString(&addr, addrStr, kNetDefaultServerPort);
NetLogConnConnect(addr, s_srvType);
}
}
//============================================================================
static void IniChangeCallback (const wchar fullPath[]) {
Ini * ini = IniOpen(fullPath);
ParseIni(ini);
IniClose(ini);
}
//============================================================================
static unsigned TimerCallback (void *) {
LISTDECL(LogConnEventNode, link) sendList;
unsigned sleepMs = kAsyncTimeInfinite;
s_critsect.Enter();
{
int allowedNumTrans = kMaxNumberOfTransactions - s_perf[kNlCliNumPendingSaves]; // find the number of transactions that we can send based on the number in transit, and the max number allowed
if(allowedNumTrans < 0) // this could be negative, if so set to zero
allowedNumTrans = 0;
dword currTime = TimeGetMs();
LogConnEventNode *hash;
int timeDiff;
// Add pending saves, up to the max allowed per update
for(;;) {
if(!allowedNumTrans && s_running) {
sleepMs = 5000; // we are at our max number of transactions sleep for 5 seconds and try again
break;
}
hash = s_eventQueue.Head();
if(!hash)
break; // no messages left. We will wait until another message comes in before another timer update
timeDiff = hash->sendTimeMs - currTime;
// nodes are naturally ordered by increasing sendTimeMs
if(!s_running || (timeDiff <= 0)) {
sendList.Link(hash);
--allowedNumTrans;
}
else {
sleepMs = timeDiff;
break;
}
}
}
s_critsect.Leave();
while(LogConnEventNode *node = sendList.Head()) {
LogMsgTrans * trans = SRV_TRANS_ALLOC(LogMsgTrans);
trans->msgBuffer = node->msg;
if (NetLogConn * conn = GetConnIncRef()) {
conn->SendRequest(trans, node->msg);
conn->DecRef();
}
else {
trans->TransCancel(kNetErrTimeout);
}
delete node;
}
return sleepMs;
}
//============================================================================
static unsigned CalcArgsLength (const NetLogEvent &event, va_list args) {
unsigned length = 0;
unsigned paramType = kNumLogParamTypes; // invalidate
unsigned field = 0;
for(unsigned i = 0; i < event.numFields * 2; ++i) {
if(!(i % 2)) {
paramType = va_arg(args, unsigned);
continue;
}
//validate parameter type
if(paramType != (unsigned)event.fields[field].type) {
length = 0;
LogMsg( kLogError, "Log parameter types do not match for event: %s parameter: %s?", event.eventName, event.fields[field].name);
break;
}
switch(event.fields[field].type) {
case kLogParamInt: {
va_arg(args, int);
length += sizeof(int);
}
break;
case kLogParamUnsigned: {
va_arg(args, unsigned);
length += sizeof(unsigned);
}
break;
case kLogParamFloat: {
va_arg(args, float);
length += sizeof(float);
}
break;
case kLogParamLong: {
va_arg(args, long);
length += sizeof(long);
}
break;
case kLogParamLongLong: {
va_arg(args, long long);
length += sizeof(long long);
}
break;
case kLogParamUuid: {
va_arg(args, Uuid);
length += sizeof(Uuid);
}
break;
case kLogParamStringW: {
wchar *str = va_arg(args, wchar *);
if(!str)
str = L"";
length += StrBytes(str);
}
break;
default:
hsAssert(false, "Unknown argument type in log statement");
return 0;
}
++field;
}
return length;
}
/*****************************************************************************
*
* NetLogConn
*
***/
//============================================================================
NetLogConn::NetLogConn (const NetAddress & addr, ESrvType srvType)
: netaddr(addr),
srvType(srvType)
{
AtomicAdd(&s_perf[kNlCliNumConn], 1);
SetAutoPing();
AutoReconnect();
}
//============================================================================
NetLogConn::~NetLogConn () {
AtomicAdd(&s_perf[kNlCliNumConn], -1);
}
//============================================================================
void NetLogConn::Connect (
AsyncCancelId * cancelId,
FAsyncNotifySocketProc notifyProc,
void * param
) {
// Connect to remote server
Srv2Log_Connect connect;
connect.hdr.connType = kConnTypeSrvToLog;
connect.hdr.hdrBytes = sizeof(connect.hdr);
connect.hdr.buildId = BuildId();
connect.hdr.buildType = BuildType();
connect.hdr.branchId = BranchId();
connect.hdr.productId = ProductId();
connect.data.dataBytes = sizeof(connect.data);
connect.data.buildId = BuildId();
connect.data.srvType = srvType;
connect.data.buildType = BuildType();
connect.data.productId = ProductId();
AsyncSocketConnect(
cancelId,
netaddr,
notifyProc,
param,
&connect,
sizeof(connect)
);
}
/*****************************************************************************
*
* LogMsgTrans
*
***/
//============================================================================
LogMsgTrans::LogMsgTrans ()
: msgBuffer(nil)
{
AtomicAdd(&s_perf[kNlCliNumTrans], 1);
}
//============================================================================
LogMsgTrans::~LogMsgTrans () {
AtomicAdd(&s_perf[kNlCliNumTrans], -1);
}
//============================================================================
bool LogMsgTrans::OnTransReply (
ENetError * error,
SrvMsgHeader * msg
) {
ref(msg);
bool result;
if (msg->protocolId != kNetProtocolSrv2Log) {
result = SrvTrans::OnTransReply(error, msg);
}
else {
result = true;
}
if(IS_NET_ERROR(*error) && s_running) {
AddEventNode(msgBuffer);
}
else {
FREE(msgBuffer);
}
return true;
}
/*****************************************************************************
*
* LogConnEventNode
*
***/
//============================================================================
LogConnEventNode::LogConnEventNode (Srv2Log_LogMsg *msg, unsigned sendTimeMs)
: msg(msg),
sendTimeMs(sendTimeMs)
{
}
/*****************************************************************************
*
* Protected
*
***/
//============================================================================
void NetLogCliInitialize (ESrvType srvType) {
s_running = true;
s_srvType = srvType;
AsyncTimerCreate(
&s_timer,
TimerCallback,
kAsyncTimeInfinite,
nil
);
IniChangeAdd(L"plServer", IniChangeCallback, &s_change);
}
//============================================================================
void NetLogCliShutdown () {
s_running = false;
if(s_change) {
IniChangeRemove(s_change, true);
s_change = false;
}
if(s_timer) {
AsyncTimerDeleteCallback(s_timer, TimerCallback);
s_timer = nil;
}
NetLogConnDisconnect();
}
//============================================================================
void NetLogCliDestroy () {
while(s_perf[kNlCliNumTrans])
AsyncSleep(10);
while(s_perf[kNlCliNumConn])
AsyncSleep(10);
}
//============================================================================
void NetLogCliSendEvent (const NetLogEvent &event, va_list args) {
Srv2Log_LogMsg *msg;
unsigned length = CalcArgsLength(event, args);
if(!length)
return;
CSrvPackBuffer pack(
sizeof(*msg) +
length
);
msg = (Srv2Log_LogMsg *) pack.Alloc(sizeof(*msg));
msg->transId = 0;
msg->protocolId = kNetProtocolSrv2Log;
msg->messageId = kSrv2Log_LogMsg;
msg->eventType = event.logEventType;
msg->timestamp = TimeGetLocalTime();
unsigned field = 0;
unsigned paramType = kNumLogParamTypes;
// if we get here the template parameters have already been validated by CalcLength, no need to do that again.
for(unsigned i = 0; i < event.numFields * 2; ++i) {
if(!(i % 2)) {
paramType = va_arg(args, unsigned);
continue;
}
switch(event.fields[field].type) {
case kLogParamInt: {
int i = va_arg(args, int);
pack.AddData(&i, sizeof(int));
}
break;
case kLogParamUnsigned: {
unsigned u = va_arg(args, unsigned);
pack.AddData(&u, sizeof(unsigned));
}
break;
case kLogParamFloat: {
float f = va_arg(args, float);
pack.AddData(&f, sizeof(float));
}
break;
case kLogParamLong: {
long l = va_arg(args, long);
pack.AddData(&l, sizeof(long));
}
break;
case kLogParamLongLong: {
long long ll = va_arg(args, long long);
pack.AddData(&ll, sizeof(long long));
}
break;
case kLogParamUuid: {
Uuid uuid = va_arg(args, Uuid);
pack.AddData(&uuid, sizeof(Uuid));
}
break;
case kLogParamStringW: {
wchar *str = va_arg(args, wchar *);
if(!str)
str = L"";
pack.AddString(str);
}
break;
}
++field;
}
msg->messageBytes = pack.Size();
AddEventNode(msg);
}

View File

@ -0,0 +1,587 @@
/*==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/pnNetLog/pnNlSrv.cpp
*
***/
#include "Pch.h"
#pragma hdrstop
/*****************************************************************************
*
* Private
*
***/
struct EventHash {
unsigned eventType;
ESrvType srvType;
inline EventHash (
unsigned eventType,
ESrvType srvType
);
inline dword GetHash () const;
inline bool operator== (const EventHash & rhs) const;
};
struct NetLogEventHash : EventHash {
const NetLogEvent * event;
NetLogEventHash(
unsigned eventType,
ESrvType srvType,
const NetLogEvent *event
);
HASHLINK(NetLogEventHash) link;
};
struct LogConn : SrvConn {
LINK(LogConn) link;
ESrvType srvType;
unsigned buildId;
NetAddressNode addr;
unsigned buildType;
unsigned productId;
// Ctor
LogConn (
AsyncSocket sock,
void ** userState,
NetAddressNode nodeNumber,
unsigned buildId,
ESrvType srvType,
unsigned buildType,
unsigned productId
);
~LogConn ();
bool OnSrvMsg (SrvMsgHeader * msg);
void OnDisconnect ();
bool Recv_Srv2Log_LogMsg( const Srv2Log_LogMsg & msg );
};
/*****************************************************************************
*
* Private Data
*
***/
static IniChangeReg * s_change;
static long s_perf[kNlSrvNumPerf];
static CCritSect s_critsect;
static bool s_running;
static LISTDECL(LogConn, link) s_conns;
void (*NetLogSrvCallback)(const NetLogEvent *event, const ARRAY(wchar) &, unsigned, NetAddressNode &, qword, unsigned, unsigned ) ;
/*****************************************************************************
*
* Private Functions
*
***/
//============================================================================
static void ParseIni (Ini * ini) {
unsigned iter;
const IniValue *value;
value = IniGetFirstValue(
ini,
L"",
L"",
&iter
);
}
//============================================================================
static void IniChangeCallback (const wchar fullPath[]) {
Ini * ini = IniOpen(fullPath);
ParseIni(ini);
IniClose(ini);
}
//===========================================================================
static bool SocketNotifyProc (
AsyncSocket sock,
EAsyncNotifySocket code,
AsyncNotifySocket * notify,
void ** userState
) {
// If the socket is successfully connected then only
// kNotifySocketListenSuccess will arrive here, as
// the service routine will be changed by SrvConn.
if (code != kNotifySocketListenSuccess) {
if (code == kNotifySocketDisconnect)
AsyncSocketDelete(sock);
return false;
}
// TODO: Verify this is from a valid server
AsyncNotifySocketListen * listen = (AsyncNotifySocketListen *) notify;
EServerRights rights = SrvIniGetServerRights(listen->remoteAddr);
if (rights < kSrvRightsServer) {
LogMsgDebug("LogConn: insufficient server rights");
AtomicAdd(&s_perf[kNlSrvPerfConnDenied], 1);
return false;
}
NetAddressNode nodeNumber = NetAddressGetNode(listen->remoteAddr);
// Parse the connect message
Srv2Log_ConnData connect;
if (!Srv2LogValidateConnect(listen, &connect)) {
LogMsgDebug("LogConn: invalid connect packet");
AtomicAdd(&s_perf[kNlSrvPerfConnDenied], 1);
return false;
}
// Create connection record
LogConn * conn = SRV_CONN_ALLOC(LogConn)(
sock,
userState,
nodeNumber,
connect.buildId,
(ESrvType) connect.srvType,
connect.buildType,
connect.productId
);
// Add this connection
bool result;
s_critsect.Enter();
{
s_conns.Link(conn);
result = s_running;
}
s_critsect.Leave();
return result;
}
/*****************************************************************************
*
* LogConn implementation
*
***/
//============================================================================
LogConn::LogConn (
AsyncSocket sock,
void ** userState,
NetAddressNode nodeNumber,
unsigned buildId,
ESrvType srvType,
unsigned buildType,
unsigned productId
) : srvType(srvType),
buildId(buildId),
buildType(buildType),
productId(productId)
{
ref(nodeNumber);
AtomicAdd(&s_perf[kNlSrvPerfConnCount], 1);
SetAutoTimeout();
NotifyListen(sock, userState);
addr = nodeNumber;
}
//============================================================================
LogConn::~LogConn () {
AtomicAdd(&s_perf[kNlSrvPerfConnCount], -1);
}
//============================================================================
void LogConn::OnDisconnect () {
// Accepting side just destroys the connection. Connecting side
// will reconnect if that's what should happen.
Destroy();
}
//============================================================================
bool LogConn::OnSrvMsg (SrvMsgHeader * msg) {
// Pass along messages not intended for us
if (msg->protocolId != kNetProtocolSrv2Log)
return SrvConn::OnSrvMsg(msg);
bool status = false;
#define DISPATCH(a) case k##a: status = Recv_##a(*(const a*)msg); break
switch (msg->messageId) {
DISPATCH(Srv2Log_LogMsg);
default:
status = false;
break;
}
#undef DISPATCH
return status;
}
//============================================================================
bool LogConn::Recv_Srv2Log_LogMsg(const Srv2Log_LogMsg & msg ) {
CSrvUnpackBuffer unpack(&msg, msg.messageBytes);
(void)unpack.GetData(sizeof(msg));
unsigned length = 0;
ARRAY(wchar) databuf;
wchar data[256];
const void *pData = 0;
SendReply(msg.transId, kNetSuccess);
if(!s_running)
return true;
// WARNING: each parameter type needs to be able to handle the case where GetData returns a nil pointer for backward compatability
const NetLogEvent *event = NetLogFindEvent(msg.eventType, srvType);
if(event) {
for(unsigned i = 0; i < event->numFields; ++i) {
if(!event->fields[i].name)
{
LogMsg(kLogError, "Failed logging event because of nil param name: %s", event->eventName);
return true;
}
switch(event->fields[i].type) {
case kLogParamInt: {
int i = 0;
pData = unpack.GetData(sizeof(int));
if(!pData)
continue;
i = *(int *)pData;
StrPrintf(data, arrsize(data), L"%d", i);
length += StrLen(data) + 1;
}
break;
case kLogParamUnsigned: {
unsigned u = 0;
pData = unpack.GetData(sizeof(unsigned));
if(!pData)
continue;
u = *(unsigned *)pData;
StrPrintf(data, arrsize(data), L"%d", u);
length += StrLen(data) + 1;
}
break;
case kLogParamFloat: {
float f = 0;
pData = unpack.GetData(sizeof(float));
if(!pData)
continue;
f = *(float *)pData;
StrPrintf(data, arrsize(data), L"%f", f);
length += StrLen(data) + 1;
}
break;
case kLogParamLong: {
long l = 0;
pData = unpack.GetData(sizeof(long));
if(!pData)
continue;
l = *(long *)pData;
StrPrintf(data, arrsize(data), L"%ld", l);
length += StrLen(data) + 1;
}
break;
case kLogParamLongLong: {
long long ll = 0;
pData = unpack.GetData(sizeof(long));
if(!pData)
continue;
ll = *(long *)pData;
StrPrintf(data, arrsize(data), L"%lld", ll);
length += StrLen(data) + 1;
}
break;
case kLogParamUuid: {
Uuid uuid = 0;
pData = unpack.GetData(sizeof(Uuid));
if(!pData)
continue;
uuid = *(Uuid *)pData;
StrPrintf(data, arrsize(data), L"%s", uuid.data);
length += StrLen(data) + 1;
}
break;
case kLogParamStringW: {
const wchar *str = unpack.GetString();
if(!str) {
continue;
}
length += StrLen(str) + 1;
}
break;
}
length += StrLen(event->fields[i].name) + 1; // this must happen after the parameter check so we can opt out of saving a non existant parameter
}
databuf.Reserve(length + 1);
{
CSrvUnpackBuffer unpack(&msg, msg.messageBytes);
(void)unpack.GetData(sizeof(msg));
for(unsigned i = 0; i < event->numFields; ++i){
// the parameter name needs to be written before the data. Also, we need to be able to opt out of writing a parameter.
switch(event->fields[i].type) {
case kLogParamInt: {
pData = unpack.GetData(sizeof(int));
if(!pData)
continue;
int val = *(int *)pData;
// log event name
databuf.Add(event->fields[i].name, StrLen(event->fields[i].name));
databuf.Add(0);
// log event data
StrPrintf(data, arrsize(data), L"%d", val);
databuf.Add(data, StrLen(data));
databuf.Add(0);
}
break;
case kLogParamUnsigned: {
pData = unpack.GetData(sizeof(unsigned));
if(!pData)
continue;
unsigned u = *(unsigned *)pData;
// log event name
databuf.Add(event->fields[i].name, StrLen(event->fields[i].name));
databuf.Add(0);
// log event data
StrPrintf(data, arrsize(data), L"%d", u);
databuf.Add(data, StrLen(data));
databuf.Add(0);
}
break;
case kLogParamFloat: {
pData = unpack.GetData(sizeof(float));
if(!pData)
continue;
float f = *(float *)pData;
// log event name
databuf.Add(event->fields[i].name, StrLen(event->fields[i].name));
databuf.Add(0);
// log event data
StrPrintf(data, arrsize(data), L"%f", f);
databuf.Add(data, StrLen(data));
databuf.Add(0);
}
break;
case kLogParamLong: {
pData = unpack.GetData(sizeof(long));
if(!pData)
continue;
long l = *(long *)pData;
// log event name
databuf.Add(event->fields[i].name, StrLen(event->fields[i].name));
databuf.Add(0);
// log event data
StrPrintf(data, arrsize(data), L"%ld", l);
databuf.Add(data, StrLen(data));
databuf.Add(0);
}
break;
case kLogParamLongLong: {
pData = unpack.GetData(sizeof(long long));
if(!pData)
continue;
long long ll = *(long long *)pData;
// log event name
databuf.Add(event->fields[i].name, StrLen(event->fields[i].name));
databuf.Add(0);
// log event data
StrPrintf(data, arrsize(data), L"%lld", ll);
databuf.Add(data, StrLen(data));
databuf.Add(0);
}
break;
case kLogParamUuid: {
pData = unpack.GetData(sizeof(Uuid));
if(!pData)
continue;
Uuid uuid = *(Uuid *)pData;
// log event name
databuf.Add(event->fields[i].name, StrLen(event->fields[i].name));
databuf.Add(0);
// log event data
GuidToString(uuid, data, arrsize(data));
databuf.Add(data, StrLen(data));
databuf.Add(0);
}
break;
case kLogParamStringW: {
const wchar *str = unpack.GetString();
if(!str) {
continue;
}
// log event name
databuf.Add(event->fields[i].name, StrLen(event->fields[i].name));
databuf.Add(0);
// log event data
databuf.Add(str, StrLen(str));
databuf.Add(0);
}
break;
}
}
}
databuf.Add(0);
if(NetLogSrvCallback) {
NetLogSrvCallback(
event,
databuf,
buildId,
addr,
msg.timestamp,
productId,
buildType
);
}
}
else
{
LogMsg(kLogError, "Unable to log event - event not found. type: %d from server: %d. If it is a new event the log server needs to be updated.", msg.eventType, srvType);
}
return true;
}
/*****************************************************************************
*
* Module exports
*
***/
//============================================================================
void NetLogSrvInitialize () {
s_running = true;
AsyncSocketRegisterNotifyProc(
kConnTypeSrvToLog,
SocketNotifyProc,
0, // Accept all buildIds
0, // Accept all buildTypes
0, // Accept all branchIds
0 // Accept all product Ids
);
IniChangeAdd(L"Log", IniChangeCallback, &s_change);
}
//============================================================================
void NetLogSrvShutdown () {
if(s_change) {
IniChangeRemove(s_change, true);
s_change = false;
}
s_running = false;
AsyncSocketUnregisterNotifyProc(
kConnTypeSrvToLog,
SocketNotifyProc,
0, // Accept all buildIds
0,
0, // Accept all branchIds
0
);
}
//============================================================================
void NetLogSrvDestroy () {
while(s_perf[kNlSrvPerfConnCount])
AsyncSleep(10);
}
//============================================================================
void NetLogSrvRegisterCallback( void (*NlSrvCallback)(const NetLogEvent *, const ARRAY(wchar) &, unsigned, NetAddressNode &, qword, unsigned, unsigned )) {
NetLogSrvCallback = NlSrvCallback;
}
//============================================================================
void LogConnIncRef (LogConn * conn) {
conn->IncRef();
}
//============================================================================
void LogConnDecRef (LogConn * conn) {
conn->DecRef();
}
/*****************************************************************************
*
* Public exports
*
***/
//============================================================================
long NetLogSrvGetPerf (unsigned index) {
ASSERT(index < kNlSrvNumPerf);
return s_perf[index];
}