Skip to content

Packet Flow Server

Joseph W Becher edited this page Nov 26, 2017 · 1 revision

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;
};
Clone this wiki locally