-
Notifications
You must be signed in to change notification settings - Fork 15
Packet Flow Server
We start in MCServer. In main, of course, because that's where sane programs start
ConnectionInfo *myOCI;
Wait, what's a ConnectionInfo
? It lives in MCCommon
struct ConnectionInfo : public DBSpamTiming
{
DWORD custID;
DWORD persID;
char persName[25];
ProcContext *c;
ConnectionInfo() : DBSpamTiming(), custID(0), persID(0), c(NULL)
{
persName[0] = 0;
}
};
Ok, Carry on.
MessageNode *node = NULL;
And a MessageNode
? It's pretty complex, but it lives in MessageNode
myOCI = CreateReplacmentDBConnection();
BSUCCESS bSuccess = DoSetup( myOCI );
HANDLE handle = (HANDLE) _beginthreadex( NULL, 0, ScheduledProcessing, NULL, 0, &threadID);
handle = (HANDLE) _beginthreadex( NULL, 0, ReadInput, NULL, 0, &threadID);
That's all that happens. We run setup. We start two threads
What does setup do?
PoolInitializer poolInit;
bool bSuccess = MCCommon_InitCustPersInfoLookup( );
server = new SocketMgrCompletion;
commResult = server->Initialize(init);
commResult = OpenClientPort();
threadPool = new ThreadPool;
poolInit.processCallback= ProcessInput;
threadPool->Initialize(poolInit);
gldAuthenticators = new AuthenticatorList(totalGLDAuthenticators);
GLDProxyClient *theAuthenticator = NULL;
gldAuthenticators->Push(theAuthenticator);
This is important, especially theAuthenticator
, but let's get back to this. Lets see if we can figure out what port the client port is.
It opens the MC_COP_CLIENT_PORT
which is 43300. So we know that port is part of COP.
Let's see what happens when data goes to the processCallback.
processCallback gets called over in ThreadPool as part of Process()
. Where does it get its data from? Process()
is called by StartProcess()
That method isn't called by anything, but it's very close to the os, so it probably receives the packets natively. Let's see what we do with them.
We might be getting a little low-level ourselves at this point, but we need to know where the data in the packet goes.
ThreadInit * init = (ThreadInit *) ptr;
ThreadInfo * info = init->info;
What's a ThreadInit?
struct ThreadInit // just used locally
{
ThreadInfo *info;
ThreadPool *This;
HANDLE event;
};
MessageNode *msg = (MessageNode*) info->data;
bool bFatalExit = processCallback( msg, (ConnectionInfo*)info->setupData );
Ok. We pass a MessageNode, and an empty structure to put some data in. This ThreadInfo
is mainly for timing, so we can (probably) ignore it. Let's see.
ProcessInput()
is back in MCServer. It starts out with preDecryptMsgNo = -1
We want to check if CLIENT_DECRYPTS_AND_DECOMPRESSES
is set. It's not, but it seems like it should be, so let's assume it is.
So lets decrypt the MessageNode buffer.
BSUCCESS bSuccess = DecryptDecompressMsg( node, info, preDecryptMsgNo );
We only want to decrypt if the message header has a valid MCOTS sig.
If it does, let's reset the preDecryptMsgNo
to the encrypted msgId. This will help us see if it really was encrypted if something goes wrong.
preDecryptMsgNo = *(WORD*)msg->buffer;
If this is an internal server message it's not encrypted.
Let's get the related connection for this message.
Connection * con = server->GetConnection( msg->toFrom );
====================================
How does the packet get a toFrom
?
====================================
Then we need to check if encryption is switched on for this connection.
if (con->useEncryption)
We need to check that the start of the MessageNode bugger is a valid header.
BaseMsgHeader * msg = (BaseMsgHeader *) node->buffer;
This really basic, but let's document the header anyway
struct BaseMsgHeader
{
WORD msgNo;
};