Actually communicates with the MC client!
This commit is contained in:
parent
6db5d80e97
commit
6dfe7f3e6e
11 changed files with 185 additions and 22 deletions
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
11
src/packets/C2SFEServerListPing.cpp
Normal file
11
src/packets/C2SFEServerListPing.cpp
Normal 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);
|
||||
}
|
||||
}
|
22
src/packets/C2SFEServerListPing.h
Normal file
22
src/packets/C2SFEServerListPing.h
Normal 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
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Reference in a new issue