Actually communicates with the MC client!

This commit is contained in:
q3k 2012-11-24 15:49:15 +01:00
parent 6db5d80e97
commit 6dfe7f3e6e
11 changed files with 185 additions and 22 deletions

View file

@ -1,12 +1,12 @@
#include "Client.h"
using namespace umcs;
CClient::CClient(TVector<unsigned short> Username)
CClient::CClient(utf8str Username)
{
m_Username = Username;
}
const TVector<unsigned short> CClient::GetUsername(void)
const utf8str CClient::GetUsername(void)
{
return m_Username;
}

View file

@ -6,10 +6,10 @@
namespace umcs {
class CClient {
private:
TVector<unsigned short> m_Username;
utf8str m_Username;
public:
CClient(TVector<unsigned short> m_Username);
const TVector<unsigned short> GetUsername(void);
CClient(utf8str m_Username);
const utf8str GetUsername(void);
};
};

View file

@ -5,6 +5,7 @@ using namespace umcs;
#include <cstring>
#include "packets/C2S02Handshake.h"
#include "packets/C2SFEServerListPing.h"
#include "packets/GenericS2CPacket.h"
#include "utf8.h"
@ -31,59 +32,147 @@ void CClientConnection::FillReadBuffer(unsigned char *Data, unsigned int Length)
LOG("Buffer overflow. Shit.\n", 0);
else
{
LOG("CClientConnection got %i bytes.\n", Length);
memcpy(m_Buffer + m_BufferPosition, Data, Length);
m_BufferPosition += Length;
LOG("m_BufferPosition now is %i.\n", m_BufferPosition);
}
}
int CClientConnection::Communicate(void)
{
LOG("CClientConnection::Communicate m_BufferPosition = %i\n", m_BufferPosition);
if (!m_InPacket)
{
char PacketID = m_Buffer[0];
switch (m_State)
unsigned char PacketID = m_Buffer[0];
LOG("Received packet ID 0x%02x\n", PacketID);
// respond to a 0xFE (server list ping) re the moral responsibility to reduce the flow of money towards Mexico, which goes into the hands of criminals" (economist.com) the moral responsibility to reduce the flow of money towards Mexico, which goes into the hands of criminals" (economist.com)quest regardless of the state
if (PacketID == 0xFE)
{
case CONNECTED:
LOG("0xfe!\n", 0);
m_CurrentPacket = new C2SFEServerListPing(m_Buffer);
m_InPacket = true;
}
else
{
switch (m_State)
{
if (PacketID != 2)
case CONNECTED:
{
LOG("Error: Unexpected packet ID %i on CONNECT state.\n", PacketID);
return -1;
if (PacketID != 0x02)
{
LOG("Error: Unexpected packet ID %i on CONNECT state.\n", PacketID);
return -1;
}
m_CurrentPacket = new C2S02Handshake(m_Buffer);
m_InPacket = true;
}
m_CurrentPacket = new C2S02Handshake(m_Buffer + 1);
m_InPacket = true;
}
}
}
else
//else
{
// continue packet
LOG("CClientConnection::Communicate m_BufferPosition = %i\n", m_BufferPosition);
m_CurrentPacket->SetDataLength(m_BufferPosition);
int Result = m_CurrentPacket->Process();
if (Result != -1)
printf("::Process result: %i\n", Result);
if (Result >= 0)
{
if (Result > 0)
{
// some data left over in the buffer... move it to the front
LOG("%i bytes left over in buffer.\n", Result);
unsigned int DataStart = m_BufferPosition - Result;
for (unsigned int i = 0; i < Result; i++)
m_Buffer[i] = m_Buffer[DataStart + i];
m_BufferPosition = Result;
}
// packet received? logic time!
switch (m_CurrentPacket->GetPacketID())
{
// HANDSHAKE
case 2:
case 0x02:
{
C2S02Handshake *Packet = (C2S02Handshake *)m_CurrentPacket;
LOG("Got handshake for protocol version %i\n", ((C2S02Handshake *)m_CurrentPacket)->GetProtocolVersion());
if (((C2S02Handshake *)m_CurrentPacket)->GetProtocolVersion() != 49)
{
LOG("... that's not a version we support.\n", 0);
return -1;
}
LOG(" Username: %s\n", &(((C2S02Handshake *)m_CurrentPacket)->GetUsername()[0]));
utf8str Username = Packet->GetUsername();
Username.push_back(0);
LOG(" Username: %s\n", &(Username[0]));
//m_Client = new CClient(Username16);
m_State = HANDSHAKE;
m_InPacket = false;
SendToClient(CGenericS2CPacket::Serialize(S2CKICK, &MakeUTF8("Bye!")));
SendToClient(CGenericS2CPacket::Serialize(S2CKICK, &MakeUTF8("Sorry, that doesn't work yet!")));
delete Packet;
m_InPacket = false;
m_CurrentPacket = 0;
break;
}
// SERVER LIST PING
case 0xFE:
{
C2SFEServerListPing *Packet = (C2SFEServerListPing *)m_CurrentPacket;
if (Packet->GetMagic() != 1)
{
LOG("Weird server list ping magic %i\n", Packet->GetMagic());
return -1;
}
// we have to use custom serialization code here,
// because the response contains an illegal unicode
// character;
utf8str Response;
// protocol
AppendUTF8(Response, "49");
Response.push_back(0);
// MC version
AppendUTF8(Response, "1.4.4");
Response.push_back(0);
// MOTD
AppendUTF8(Response, "A umcs server.");
Response.push_back(0);
// Player Count
AppendUTF8(Response, "0");
Response.push_back(0);
AppendUTF8(Response, "20");
Response.push_back(0);
TVector<unsigned char> Buffer;
Buffer.push_back(0xFF);
unsigned int Length = Response.size() + 3;
Buffer.push_back(Length >> 8);
Buffer.push_back(Length & 0xFF);
Buffer.push_back(0x00);
Buffer.push_back(0xA7);
Buffer.push_back(0x00);
Buffer.push_back(0x31);
Buffer.push_back(0x00);
Buffer.push_back(0x00);
for (auto It = Response.begin(); It != Response.end(); It++)
{
printf("packet %02x\n", *It);
Buffer.push_back(0);
Buffer.push_back(*It);
}
SendToClient(Buffer);
}
}
}
else if (Result == -2)
{
LOG("Packet returned fatal error when processing. Disconnecting client.\n", 0);
return -1;
}
}
return 0;
}
@ -96,5 +185,11 @@ CClientConnection::~CClientConnection(void)
void CClientConnection::SendToClient(TVector<unsigned char> Buffer)
{
printf("---------> SENDING TO CLIENT\n");
for (auto It = Buffer.begin(); It != Buffer.end(); It++)
{
printf("%02x ", *It);
}
printf("\n");
send(m_Socket, &Buffer[0], Buffer.size(), 0);
}

View file

@ -25,6 +25,7 @@ namespace umcs {
CClient *m_Client;
void SendToClient(TVector<unsigned char>Bufer);
void SlideBufferWindow(unsigned int RemainingBytes);
protected:
TSocket m_Socket;
EClientConnectionState m_State;

View file

@ -1,7 +1,7 @@
CXXFLAGS="-std=c++0x"
OBJECTS := ServerLoop.o ClientConnection.o Client.o main.o \
packets/GenericC2SPacket.o packets/C2S02Handshake.o \
packets/GenericC2SPacket.o packets/C2S02Handshake.o packets/C2SFEServerListPing.o \
packets/GenericS2CPacket.o
all: $(OBJECTS)

View file

@ -79,7 +79,7 @@ int CServerLoop::Run(void)
bool Continue = true;
while (Continue)
{
int Result = Select(1000);
int Result = Select(100000);
if (FD_ISSET(m_GameSocket, &m_RSockets))
{
LOG("New connection!\n", 0);

View file

@ -24,4 +24,9 @@ inline utf8str MakeUTF8(const char *String)
return utf8str((const unsigned char *)String, (const unsigned char*)String + strlen(String));
}
inline void AppendUTF8(utf8str &Target, const char *String)
{
Target.insert(Target.end(), String, String + strlen(String));
}
#endif

View file

@ -0,0 +1,11 @@
#include "C2SFEServerListPing.h"
using namespace umcs;
bool C2SFEServerListPing::ReadField(unsigned int Field)
{
switch (Field)
{
case 0:
return ReadByte(m_Magic);
}
}

View file

@ -0,0 +1,22 @@
#ifndef __C2SFE_SERVERLISTPING_H__
#define __C2SFE_SERVERLISTPING_H__
#include "GenericC2SPacket.h"
#include "../config.h"
namespace umcs {
class C2SFEServerListPing : public CGenericC2SPacket {
private:
char m_Magic;
protected:
unsigned int GetNumFields(void) { return 1; };
bool ReadField(unsigned int Field);
public:
C2SFEServerListPing(unsigned char *Buffer) : CGenericC2SPacket(Buffer) { }
virtual int GetPacketID(void) { return 0xFE; }
char GetMagic(void) { return m_Magic; }
};
};
#endif

View file

@ -15,18 +15,45 @@ CGenericC2SPacket::CGenericC2SPacket(unsigned char *Buffer)
void CGenericC2SPacket::SetDataLength(unsigned int Length)
{
m_AvailableDataLength = Length;
LOG("Packet has %i bytes of data.\n", m_AvailableDataLength);
}
int CGenericC2SPacket::Process(void)
{
if (GetAvailableBytes() < 1)
{
LOG("Available bytes: %i\n", GetAvailableBytes());
return -1;
}
if (m_CurrentByte == 0)
{
LOG("Parsing packet ID...\n", 0);
char Type;
ReadByte(Type);
if ((unsigned char)Type != GetPacketID())
{
LOG("Incorrect packetID. expexted %02x, got %02x. wat. wat. wat.\n", GetPacketID(), Type);
return -2;
}
}
for (unsigned int i = m_CurrentField; i < GetNumFields(); i++)
{
LOG("Reading field %i.\n", i);
LOG("FYI, %i available bytes.\n", GetAvailableBytes());
bool Result = ReadField(i);
if (Result)
{
m_CurrentField++; // field processed, increment current field in case we stop somewhere along the road
LOG("Field Okay.\n", 0);
}
else
{
LOG("Not enough bytes (got -1)\n", 0);
return -1; // field unprocessed - not enough data. stop for now.
}
}
LOG("All fields read.!\n", 0);
// run the callback for children classes
AllFieldsRead();
// be sure to let caller know if some data was unnecessary
@ -104,7 +131,9 @@ bool CGenericC2SPacket::ReadString(utf8str &String)
for (unsigned int i = 0; i < StringLength; i++)
{
unsigned short Unit = *(((unsigned short *)(m_Buffer + m_CurrentByte)) + 1 + i);
String16.push_back(Unit);
printf("Unit: %c\n", Unit >> 8);
// endianness swap
String16.push_back((Unit >> 8) | ((Unit << 8) & 0xFF00));
}
UTF16TO8(String16, String);

View file

@ -42,8 +42,8 @@ TVector<unsigned char> CGenericS2CPacket::Serialize(ES2CPacket PacketID, ...)
Buffer.push_back(Length & 0xFF);
for (unsigned int i = 0; i < Length; i++)
{
Buffer.push_back(String16[i] & 0xFF);
Buffer.push_back(String16[i] >> 8);
Buffer.push_back(String16[i] & 0xFF);
}
break;