diff options
-rw-r--r-- | Tools/ProtoProxy/Connection.cpp | 985 | ||||
-rw-r--r-- | Tools/ProtoProxy/Connection.h | 57 | ||||
-rw-r--r-- | VC2008/MCServer.vcproj | 8 | ||||
-rw-r--r-- | source/Blocks/BlockDirt.h | 4 | ||||
-rw-r--r-- | source/ClientHandle.cpp | 4 | ||||
-rw-r--r-- | source/Entities/ProjectileEntity.cpp | 13 | ||||
-rw-r--r-- | source/Mobs/AggressiveMonster.cpp | 2 | ||||
-rw-r--r-- | source/Mobs/Horse.cpp | 5 | ||||
-rw-r--r-- | source/Mobs/Pig.cpp | 4 | ||||
-rw-r--r-- | source/Protocol/Protocol.h | 21 | ||||
-rw-r--r-- | source/Protocol/Protocol125.h | 4 | ||||
-rw-r--r-- | source/Protocol/Protocol17x.cpp | 216 | ||||
-rw-r--r-- | source/Protocol/Protocol17x.h | 75 | ||||
-rw-r--r-- | source/Protocol/ProtocolRecognizer.cpp | 120 | ||||
-rw-r--r-- | source/Protocol/ProtocolRecognizer.h | 22 |
15 files changed, 1042 insertions, 498 deletions
diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp index b22e61816..b99415900 100644 --- a/Tools/ProtoProxy/Connection.cpp +++ b/Tools/ProtoProxy/Connection.cpp @@ -52,7 +52,7 @@ #define CLIENTSEND(...) SendData(m_ClientSocket, __VA_ARGS__, "Client") #define SERVERSEND(...) SendData(m_ServerSocket, __VA_ARGS__, "Server") -#define CLIENTENCRYPTSEND(...) SendEncryptedData(m_ClientSocket, m_ClientEncryptor, __VA_ARGS__, "Client") +#define CLIENTENCRYPTSEND(...) SendData(m_ClientSocket, __VA_ARGS__, "Client") // The client conn is always unencrypted #define SERVERENCRYPTSEND(...) SendEncryptedData(m_ServerSocket, m_ServerEncryptor, __VA_ARGS__, "Server") #define COPY_TO_SERVER() \ @@ -99,19 +99,20 @@ CLIENTENCRYPTSEND(ToClient.data(), ToClient.size()); \ break; \ } \ - case csWaitingForEncryption: \ + /* case csWaitingForEncryption: \ { \ Log("Waiting for client encryption, queued %u bytes", ToClient.size()); \ m_ClientEncryptionBuffer.append(ToClient.data(), ToClient.size()); \ break; \ } \ + */ \ } \ DebugSleep(50); \ } #define HANDLE_CLIENT_READ(Proc) \ { \ - if (!Proc()) \ + if (!Proc) \ { \ AString Leftover; \ m_ClientBuffer.ReadAgain(Leftover); \ @@ -123,7 +124,7 @@ #define HANDLE_SERVER_READ(Proc) \ { \ - if (!Proc()) \ + if (!Proc) \ { \ m_ServerBuffer.ResetRead(); \ return true; \ @@ -276,7 +277,9 @@ cConnection::cConnection(SOCKET a_ClientSocket, cServer & a_Server) : m_ClientBuffer(1024 KiB), m_ServerBuffer(1024 KiB), m_HasClientPinged(false), - m_ProtocolState(-1) + m_ServerProtocolState(-1), + m_ClientProtocolState(-1), + m_IsServerEncrypted(false) { // Create the Logs subfolder, if not already created: #if defined(_WIN32) @@ -459,7 +462,6 @@ bool cConnection::RelayFromServer(void) { m_ServerDecryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res); DataLog(Buffer, res, "Decrypted %d bytes from the SERVER", res); - m_ClientEncryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res); return CLIENTSEND(Buffer, res); } } @@ -492,13 +494,10 @@ bool cConnection::RelayFromClient(void) } case csEncryptedUnderstood: { - m_ClientDecryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res); - DataLog(Buffer, res, "Decrypted %d bytes from the CLIENT", res); return DecodeClientsPackets(Buffer, res); } case csEncryptedUnknown: { - m_ClientDecryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res); DataLog(Buffer, res, "Decrypted %d bytes from the CLIENT", res); m_ServerEncryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res); return SERVERSEND(Buffer, res); @@ -605,17 +604,20 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size) // Not a complete packet yet break; } - UInt32 PacketType; + UInt32 PacketType, PacketReadSoFar; + PacketReadSoFar = m_ClientBuffer.GetReadableSpace(); VERIFY(m_ClientBuffer.ReadVarInt(PacketType)); + PacketReadSoFar -= m_ClientBuffer.GetReadableSpace(); Log("Decoding client's packets, there are now %d bytes in the queue; next packet is 0x%0x, %u bytes long", m_ClientBuffer.GetReadableSpace(), PacketType, PacketLen); - switch (m_ProtocolState) + switch (m_ClientProtocolState) { case -1: { // No initial handshake received yet switch (PacketType) { - case 0: HANDLE_CLIENT_READ(HandleClientHandshake); break; + case 0x00: HANDLE_CLIENT_READ(HandleClientHandshake()); break; + default: HANDLE_CLIENT_READ(HandleClientUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break; } break; } // case -1 @@ -625,73 +627,62 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size) // Status query switch (PacketType) { - case 0: HANDLE_CLIENT_READ(HandleClientStatusRequest); break; - case 1: HANDLE_CLIENT_READ(HandleClientStatusPing); break; + case 0x00: HANDLE_CLIENT_READ(HandleClientStatusRequest()); break; + case 0x01: HANDLE_CLIENT_READ(HandleClientStatusPing()); break; + default: HANDLE_CLIENT_READ(HandleClientUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break; } break; } case 2: { - // Login / game + // Login switch (PacketType) { - case PACKET_BLOCK_DIG: HANDLE_CLIENT_READ(HandleClientBlockDig); break; - case PACKET_BLOCK_PLACE: HANDLE_CLIENT_READ(HandleClientBlockPlace); break; - case PACKET_S_CHAT_MESSAGE: HANDLE_CLIENT_READ(HandleClientChatMessage); break; - case PACKET_CLIENT_STATUSES: HANDLE_CLIENT_READ(HandleClientClientStatuses); break; - case PACKET_CREATIVE_INVENTORY_ACTION: HANDLE_CLIENT_READ(HandleClientCreativeInventoryAction); break; - case PACKET_DISCONNECT: HANDLE_CLIENT_READ(HandleClientDisconnect); break; - case PACKET_ENCRYPTION_KEY_RESPONSE: HANDLE_CLIENT_READ(HandleClientEncryptionKeyResponse); break; - case PACKET_ENTITY_ACTION: HANDLE_CLIENT_READ(HandleClientEntityAction); break; - case PACKET_S_KEEPALIVE: HANDLE_CLIENT_READ(HandleClientKeepAlive); break; - case PACKET_LOCALE_AND_VIEW: HANDLE_CLIENT_READ(HandleClientLocaleAndView); break; - case PACKET_PING: HANDLE_CLIENT_READ(HandleClientPing); break; - case PACKET_PLAYER_ABILITIES: HANDLE_CLIENT_READ(HandleClientPlayerAbilities); break; - case PACKET_PLAYER_ANIMATION: HANDLE_CLIENT_READ(HandleClientAnimation); break; - case PACKET_PLAYER_LOOK: HANDLE_CLIENT_READ(HandleClientPlayerLook); break; - case PACKET_PLAYER_ON_GROUND: HANDLE_CLIENT_READ(HandleClientPlayerOnGround); break; - case PACKET_PLAYER_POSITION: HANDLE_CLIENT_READ(HandleClientPlayerPosition); break; - case PACKET_PLAYER_POSITION_LOOK: HANDLE_CLIENT_READ(HandleClientPlayerPositionLook); break; - case PACKET_PLUGIN_MESSAGE: HANDLE_CLIENT_READ(HandleClientPluginMessage); break; - case PACKET_SLOT_SELECT: HANDLE_CLIENT_READ(HandleClientSlotSelect); break; - case PACKET_TAB_COMPLETION: HANDLE_CLIENT_READ(HandleClientTabCompletion); break; - case PACKET_UPDATE_SIGN: HANDLE_CLIENT_READ(HandleClientUpdateSign); break; - case PACKET_USE_ENTITY: HANDLE_CLIENT_READ(HandleClientUseEntity); break; - case PACKET_WINDOW_CLICK: HANDLE_CLIENT_READ(HandleClientWindowClick); break; - case PACKET_WINDOW_CLOSE: HANDLE_CLIENT_READ(HandleClientWindowClose); break; + case 0x00: HANDLE_CLIENT_READ(HandleClientLoginStart()); break; + case 0x01: HANDLE_CLIENT_READ(HandleClientLoginEncryptionKeyResponse()); break; + default: HANDLE_CLIENT_READ(HandleClientUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break; } break; - } // case 2 + } - default: + case 3: { - // TODO: Move this elsewhere - if (m_ClientState == csEncryptedUnderstood) - { - Log("****************** Unknown packet 0x%02x from the client while encrypted; continuing to relay blind only", PacketType); - AString Data; - m_ClientBuffer.ResetRead(); - m_ClientBuffer.ReadAll(Data); - DataLog(Data.data(), Data.size(), "Current data in the client packet queue: %d bytes", Data.size()); - m_ClientState = csEncryptedUnknown; - m_ClientBuffer.ResetRead(); - if (m_ServerState == csUnencrypted) - { - SERVERSEND(m_ClientBuffer); - } - else - { - SERVERENCRYPTSEND(m_ClientBuffer); - } - return true; - } - else + // Game: + switch (PacketType) { - Log("Unknown packet 0x%02x from the client while unencrypted; aborting connection", PacketType); - return false; + case 0x00: HANDLE_CLIENT_READ(HandleClientKeepAlive()); break; + case 0x01: HANDLE_CLIENT_READ(HandleClientChatMessage()); break; + case 0x02: HANDLE_CLIENT_READ(HandleClientUseEntity()); break; + case 0x03: HANDLE_CLIENT_READ(HandleClientPlayerOnGround()); break; + case 0x04: HANDLE_CLIENT_READ(HandleClientPlayerPosition()); break; + case 0x05: HANDLE_CLIENT_READ(HandleClientPlayerLook()); break; + case 0x06: HANDLE_CLIENT_READ(HandleClientPlayerPositionLook()); break; + case 0x07: HANDLE_CLIENT_READ(HandleClientBlockDig()); break; + case 0x08: HANDLE_CLIENT_READ(HandleClientBlockPlace()); break; + case 0x09: HANDLE_CLIENT_READ(HandleClientSlotSelect()); break; + case 0x0a: HANDLE_CLIENT_READ(HandleClientAnimation()); break; + case 0x0b: HANDLE_CLIENT_READ(HandleClientEntityAction()); break; + case 0x0d: HANDLE_CLIENT_READ(HandleClientWindowClose()); break; + case 0x0e: HANDLE_CLIENT_READ(HandleClientWindowClick()); break; + case 0x10: HANDLE_CLIENT_READ(HandleClientCreativeInventoryAction()); break; + case 0x12: HANDLE_CLIENT_READ(HandleClientUpdateSign()); break; + case 0x13: HANDLE_CLIENT_READ(HandleClientPlayerAbilities()); break; + case 0x14: HANDLE_CLIENT_READ(HandleClientTabCompletion()); break; + case 0x15: HANDLE_CLIENT_READ(HandleClientLocaleAndView()); break; + case 0x16: HANDLE_CLIENT_READ(HandleClientClientStatuses()); break; + case 0x17: HANDLE_CLIENT_READ(HandleClientPluginMessage()); break; + default: HANDLE_CLIENT_READ(HandleClientUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break; } - } // default + break; + } // case 3 - Game + + default: + { + Log("Receiving server packets while in an unknown protocol state (%d)!", m_ClientProtocolState); + HANDLE_CLIENT_READ(HandleClientUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); + break; + } } // switch (m_ProtocolState) m_ClientBuffer.CommitRead(); } // while (true) @@ -729,15 +720,18 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size) // Not a complete packet yet break; } - UInt32 PacketType; + UInt32 PacketType, PacketReadSoFar; + PacketReadSoFar = m_ServerBuffer.GetReadableSpace(); VERIFY(m_ServerBuffer.ReadVarInt(PacketType)); + PacketReadSoFar -= m_ServerBuffer.GetReadableSpace(); Log("Decoding server's packets, there are now %d bytes in the queue; next packet is 0x%0x, %u bytes long", m_ServerBuffer.GetReadableSpace(), PacketType, PacketLen); LogFlush(); - switch (m_ProtocolState) + switch (m_ServerProtocolState) { case -1: { Log("Receiving data from the server without an initial handshake message!"); + HANDLE_SERVER_READ(HandleServerUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break; } @@ -746,100 +740,94 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size) // Status query: switch (PacketType) { - case 0: HANDLE_SERVER_READ(HandleServerStatusResponse); break; - case 1: HANDLE_SERVER_READ(HandleServerStatusPing); break; + case 0x00: HANDLE_SERVER_READ(HandleServerStatusResponse()); break; + case 0x01: HANDLE_SERVER_READ(HandleServerStatusPing()); break; + default: HANDLE_SERVER_READ(HandleServerUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break; } break; } case 2: { - // Login / game: + // Login: + switch (PacketType) + { + case 0x00: HANDLE_SERVER_READ(HandleServerLoginDisconnect()); break; + case 0x01: HANDLE_SERVER_READ(HandleServerLoginEncryptionKeyRequest()); break; + case 0x02: HANDLE_SERVER_READ(HandleServerLoginSuccess()); break; + default: HANDLE_SERVER_READ(HandleServerUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break; + } + break; + } + + case 3: + { + // Game: switch (PacketType) { - case PACKET_ATTACH_ENTITY: HANDLE_SERVER_READ(HandleServerAttachEntity); break; - case PACKET_BLOCK_ACTION: HANDLE_SERVER_READ(HandleServerBlockAction); break; - case PACKET_BLOCK_CHANGE: HANDLE_SERVER_READ(HandleServerBlockChange); break; - case PACKET_CHANGE_GAME_STATE: HANDLE_SERVER_READ(HandleServerChangeGameState); break; - case PACKET_C_CHAT_MESSAGE: HANDLE_SERVER_READ(HandleServerChatMessage); break; - case PACKET_COLLECT_PICKUP: HANDLE_SERVER_READ(HandleServerCollectPickup); break; - case PACKET_DESTROY_ENTITIES: HANDLE_SERVER_READ(HandleServerDestroyEntities); break; - case PACKET_ENCRYPTION_KEY_REQUEST: HANDLE_SERVER_READ(HandleServerEncryptionKeyRequest); break; - case PACKET_ENCRYPTION_KEY_RESPONSE: HANDLE_SERVER_READ(HandleServerEncryptionKeyResponse); break; - case PACKET_ENTITY: HANDLE_SERVER_READ(HandleServerEntity); break; - case PACKET_ENTITY_EQUIPMENT: HANDLE_SERVER_READ(HandleServerEntityEquipment); break; - case PACKET_ENTITY_HEAD_LOOK: HANDLE_SERVER_READ(HandleServerEntityHeadLook); break; - case PACKET_ENTITY_LOOK: HANDLE_SERVER_READ(HandleServerEntityLook); break; - case PACKET_ENTITY_METADATA: HANDLE_SERVER_READ(HandleServerEntityMetadata); break; - case PACKET_ENTITY_PROPERTIES: HANDLE_SERVER_READ(HandleServerEntityProperties); break; - case PACKET_ENTITY_RELATIVE_MOVE: HANDLE_SERVER_READ(HandleServerEntityRelativeMove); break; - case PACKET_ENTITY_RELATIVE_MOVE_LOOK: HANDLE_SERVER_READ(HandleServerEntityRelativeMoveLook); break; - case PACKET_ENTITY_STATUS: HANDLE_SERVER_READ(HandleServerEntityStatus); break; - case PACKET_ENTITY_TELEPORT: HANDLE_SERVER_READ(HandleServerEntityTeleport); break; - case PACKET_ENTITY_VELOCITY: HANDLE_SERVER_READ(HandleServerEntityVelocity); break; - case PACKET_EXPLOSION: HANDLE_SERVER_READ(HandleServerExplosion); break; - case PACKET_INCREMENT_STATISTIC: HANDLE_SERVER_READ(HandleServerIncrementStatistic); break; - case PACKET_C_JOIN_GAME: HANDLE_SERVER_READ(HandleServerLogin); break; - case PACKET_C_KEEPALIVE: HANDLE_SERVER_READ(HandleServerKeepAlive); break; - case PACKET_KICK: HANDLE_SERVER_READ(HandleServerKick); break; - case PACKET_MAP_CHUNK: HANDLE_SERVER_READ(HandleServerMapChunk); break; - case PACKET_MAP_CHUNK_BULK: HANDLE_SERVER_READ(HandleServerMapChunkBulk); break; - case PACKET_MULTI_BLOCK_CHANGE: HANDLE_SERVER_READ(HandleServerMultiBlockChange); break; - case PACKET_NAMED_SOUND_EFFECT: HANDLE_SERVER_READ(HandleServerNamedSoundEffect); break; - case PACKET_PLAYER_ABILITIES: HANDLE_SERVER_READ(HandleServerPlayerAbilities); break; - case PACKET_PLAYER_ANIMATION: HANDLE_SERVER_READ(HandleServerPlayerAnimation); break; - case PACKET_PLAYER_LIST_ITEM: HANDLE_SERVER_READ(HandleServerPlayerListItem); break; - case PACKET_PLAYER_POSITION_LOOK: HANDLE_SERVER_READ(HandleServerPlayerPositionLook); break; - case PACKET_PLUGIN_MESSAGE: HANDLE_SERVER_READ(HandleServerPluginMessage); break; - case PACKET_SET_EXPERIENCE: HANDLE_SERVER_READ(HandleServerSetExperience); break; - case PACKET_SET_SLOT: HANDLE_SERVER_READ(HandleServerSetSlot); break; - case PACKET_SLOT_SELECT: HANDLE_SERVER_READ(HandleServerSlotSelect); break; - case PACKET_SOUND_EFFECT: HANDLE_SERVER_READ(HandleServerSoundEffect); break; - case PACKET_SPAWN_MOB: HANDLE_SERVER_READ(HandleServerSpawnMob); break; - case PACKET_SPAWN_NAMED_ENTITY: HANDLE_SERVER_READ(HandleServerSpawnNamedEntity); break; - case PACKET_SPAWN_OBJECT_VEHICLE: HANDLE_SERVER_READ(HandleServerSpawnObjectVehicle); break; - case PACKET_SPAWN_PAINTING: HANDLE_SERVER_READ(HandleServerSpawnPainting); break; - case PACKET_SPAWN_PICKUP: HANDLE_SERVER_READ(HandleServerSpawnPickup); break; - case PACKET_SPAWN_POSITION: HANDLE_SERVER_READ(HandleServerCompass); break; - case PACKET_TAB_COMPLETION: HANDLE_SERVER_READ(HandleServerTabCompletion); break; - case PACKET_TIME_UPDATE: HANDLE_SERVER_READ(HandleServerTimeUpdate); break; - case PACKET_UPDATE_HEALTH: HANDLE_SERVER_READ(HandleServerUpdateHealth); break; - case PACKET_UPDATE_SIGN: HANDLE_SERVER_READ(HandleServerUpdateSign); break; - case PACKET_UPDATE_TILE_ENTITY: HANDLE_SERVER_READ(HandleServerUpdateTileEntity); break; - case PACKET_WINDOW_CLOSE: HANDLE_SERVER_READ(HandleServerWindowClose); break; - case PACKET_WINDOW_CONTENTS: HANDLE_SERVER_READ(HandleServerWindowContents); break; - case PACKET_WINDOW_OPEN: HANDLE_SERVER_READ(HandleServerWindowOpen); break; + case 0x00: HANDLE_SERVER_READ(HandleServerKeepAlive()); break; + case 0x01: HANDLE_SERVER_READ(HandleServerJoinGame()); break; + case 0x02: HANDLE_SERVER_READ(HandleServerChatMessage()); break; + case 0x03: HANDLE_SERVER_READ(HandleServerTimeUpdate()); break; + case 0x04: HANDLE_SERVER_READ(HandleServerEntityEquipment()); break; + case 0x05: HANDLE_SERVER_READ(HandleServerCompass()); break; + case 0x06: HANDLE_SERVER_READ(HandleServerUpdateHealth()); break; + case 0x07: HANDLE_SERVER_READ(HandleServerRespawn()); break; + case 0x08: HANDLE_SERVER_READ(HandleServerPlayerPositionLook()); break; + case 0x09: HANDLE_SERVER_READ(HandleServerSlotSelect()); break; + case 0x0a: HANDLE_SERVER_READ(HandleServerUseBed()); break; + case 0x0b: HANDLE_SERVER_READ(HandleServerPlayerAnimation()); break; + case 0x0c: HANDLE_SERVER_READ(HandleServerSpawnNamedEntity()); break; + case 0x0d: HANDLE_SERVER_READ(HandleServerCollectPickup()); break; + case 0x0e: HANDLE_SERVER_READ(HandleServerSpawnObjectVehicle()); break; + case 0x0f: HANDLE_SERVER_READ(HandleServerSpawnMob()); break; + case 0x10: HANDLE_SERVER_READ(HandleServerSpawnPainting()); break; + case 0x11: HANDLE_SERVER_READ(HandleServerSpawnExperienceOrbs()); break; + case 0x12: HANDLE_SERVER_READ(HandleServerEntityVelocity()); break; + case 0x13: HANDLE_SERVER_READ(HandleServerDestroyEntities()); break; + case 0x14: HANDLE_SERVER_READ(HandleServerEntity()); break; + case 0x15: HANDLE_SERVER_READ(HandleServerEntityRelativeMove()); break; + case 0x16: HANDLE_SERVER_READ(HandleServerEntityLook()); break; + case 0x17: HANDLE_SERVER_READ(HandleServerEntityRelativeMoveLook()); break; + case 0x18: HANDLE_SERVER_READ(HandleServerEntityTeleport()); break; + case 0x19: HANDLE_SERVER_READ(HandleServerEntityHeadLook()); break; + case 0x1a: HANDLE_SERVER_READ(HandleServerEntityStatus()); break; + case 0x1b: HANDLE_SERVER_READ(HandleServerAttachEntity()); break; + case 0x1c: HANDLE_SERVER_READ(HandleServerEntityMetadata()); break; + case 0x1f: HANDLE_SERVER_READ(HandleServerSetExperience()); break; + case 0x20: HANDLE_SERVER_READ(HandleServerEntityProperties()); break; + case 0x21: HANDLE_SERVER_READ(HandleServerMapChunk()); break; + case 0x22: HANDLE_SERVER_READ(HandleServerMultiBlockChange()); break; + case 0x23: HANDLE_SERVER_READ(HandleServerBlockChange()); break; + case 0x24: HANDLE_SERVER_READ(HandleServerBlockAction()); break; + case 0x26: HANDLE_SERVER_READ(HandleServerMapChunkBulk()); break; + case 0x27: HANDLE_SERVER_READ(HandleServerExplosion()); break; + case 0x28: HANDLE_SERVER_READ(HandleServerSoundEffect()); break; + case 0x29: HANDLE_SERVER_READ(HandleServerNamedSoundEffect()); break; + case 0x2b: HANDLE_SERVER_READ(HandleServerChangeGameState()); break; + case 0x2d: HANDLE_SERVER_READ(HandleServerWindowOpen()); break; + case 0x2e: HANDLE_SERVER_READ(HandleServerWindowClose()); break; + case 0x2f: HANDLE_SERVER_READ(HandleServerSetSlot()); break; + case 0x30: HANDLE_SERVER_READ(HandleServerWindowContents()); break; + case 0x33: HANDLE_SERVER_READ(HandleServerUpdateSign()); break; + case 0x35: HANDLE_SERVER_READ(HandleServerUpdateTileEntity()); break; + case 0x37: HANDLE_SERVER_READ(HandleServerStatistics()); break; + case 0x38: HANDLE_SERVER_READ(HandleServerPlayerListItem()); break; + case 0x39: HANDLE_SERVER_READ(HandleServerPlayerAbilities()); break; + case 0x3a: HANDLE_SERVER_READ(HandleServerTabCompletion()); break; + case 0x3f: HANDLE_SERVER_READ(HandleServerPluginMessage()); break; + case 0x40: HANDLE_SERVER_READ(HandleServerKick()); break; + default: HANDLE_SERVER_READ(HandleServerUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break; } // switch (PacketType) break; - } // case 2 + } // case 3 - Game // TODO: Move this elsewhere default: { - if (m_ServerState == csEncryptedUnderstood) - { - Log("********************** Unknown packet 0x%02x from the server while encrypted; continuing to relay blind only", PacketType); - AString Data; - m_ServerBuffer.ResetRead(); - m_ServerBuffer.ReadAll(Data); - DataLog(Data.data(), Data.size(), "Current data in the server packet queue: %d bytes", Data.size()); - m_ServerState = csEncryptedUnknown; - m_ServerBuffer.ResetRead(); - if (m_ClientState == csUnencrypted) - { - CLIENTSEND(m_ServerBuffer); - } - else - { - CLIENTENCRYPTSEND(m_ServerBuffer); - } - return true; - } - else - { - Log("Unknown packet 0x%02x from the server while unencrypted; aborting connection", PacketType); - return false; - } + Log("Received a packet from the server while in an unknown state: %d", m_ServerProtocolState); + HANDLE_SERVER_READ(HandleServerUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); + break; } } // switch (m_ProtocolState) @@ -852,6 +840,76 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// packet handling, client-side, initial handshake: + +bool cConnection::HandleClientHandshake(void) +{ + // Read the packet from the client: + HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, ProtocolVersion); + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ServerHost); + HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, ServerPort); + HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, NextState); + m_ClientBuffer.CommitRead(); + + Log("Received an initial handshake packet from the client:"); + Log(" ProtocolVersion = %u", ProtocolVersion); + Log(" ServerHost = \"%s\"", ServerHost.c_str()); + Log(" ServerPort = %d", ServerPort); + Log(" NextState = %u", NextState); + + // Send the same packet to the server, but with our port: + cByteBuffer Packet(512); + Packet.WriteVarInt(0); // Packet type - initial handshake + Packet.WriteVarInt(ProtocolVersion); + Packet.WriteVarUTF8String(ServerHost); + Packet.WriteBEShort(m_Server.GetConnectPort()); + Packet.WriteVarInt(NextState); + AString Pkt; + Packet.ReadAll(Pkt); + cByteBuffer ToServer(512); + ToServer.WriteVarUTF8String(Pkt); + SERVERSEND(ToServer); + + m_ClientProtocolState = (int)NextState; + m_ServerProtocolState = (int)NextState; + + return true; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// packet handling, client-side, login: + +bool cConnection::HandleClientLoginEncryptionKeyResponse(void) +{ + Log("Client: Unexpected packet: encryption key response"); + return true; +} + + + + + +bool cConnection::HandleClientLoginStart(void) +{ + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, UserName); + Log("Received a login start packet from the client:"); + Log(" Username = \"%s\"", UserName.c_str()); + COPY_TO_SERVER(); + return true; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// packet handling, client-side, game: + bool cConnection::HandleClientAnimation(void) { HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, EntityID); @@ -915,7 +973,7 @@ bool cConnection::HandleClientBlockPlace(void) bool cConnection::HandleClientChatMessage(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Message); + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Message); Log("Received a PACKET_CHAT_MESSAGE from the client:"); Log(" Message = \"%s\"", Message.c_str()); COPY_TO_SERVER(); @@ -961,7 +1019,7 @@ bool cConnection::HandleClientCreativeInventoryAction(void) bool cConnection::HandleClientDisconnect(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Reason); + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Reason); Log("Received a PACKET_DISCONNECT from the client:"); Log(" Reason = \"%s\"", Reason.c_str()); COPY_TO_SERVER(); @@ -972,42 +1030,15 @@ bool cConnection::HandleClientDisconnect(void) -bool cConnection::HandleClientEncryptionKeyResponse(void) -{ - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, EncKeyLength); - AString EncKey; - if (!m_ClientBuffer.ReadString(EncKey, EncKeyLength)) - { - return true; - } - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, EncNonceLength); - AString EncNonce; - if (!m_ClientBuffer.ReadString(EncNonce, EncNonceLength)) - { - return true; - } - if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN)) - { - Log("Client: Too long encryption params"); - return true; - } - StartClientEncryption(EncKey, EncNonce); - return true; -} - - - - - bool cConnection::HandleClientEntityAction(void) { HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, PlayerID); HANDLE_CLIENT_PACKET_READ(ReadByte, Byte, ActionType); - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, UnknownHorseVal); + HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, HorseJumpBoost); Log("Received a PACKET_ENTITY_ACTION from the client:"); Log(" PlayerID = %d", PlayerID); Log(" ActionType = %d", ActionType); - Log(" UnknownHorseVal = %d (0x%08x)", UnknownHorseVal, UnknownHorseVal); + Log(" HorseJumpBoost = %d (0x%08x)", HorseJumpBoost, HorseJumpBoost); COPY_TO_SERVER(); return true; } @@ -1016,43 +1047,6 @@ bool cConnection::HandleClientEntityAction(void) -bool cConnection::HandleClientHandshake(void) -{ - // Read the packet from the client: - HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, ProtocolVersion); - HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ServerHost); - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, ServerPort); - HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, NextState); - m_ClientBuffer.CommitRead(); - - Log("Received an initial handshake packet from the client:"); - Log(" ProtocolVersion = %u", ProtocolVersion); - Log(" ServerHost = \"%s\"", ServerHost.c_str()); - Log(" ServerPort = %d", ServerPort); - Log(" NextState = %u", NextState); - - // Send the same packet to the server, but with our port: - cByteBuffer Packet(512); - Packet.WriteVarInt(0); // Packet type - initial handshake - Packet.WriteVarInt(ProtocolVersion); - Packet.WriteVarUTF8String(ServerHost); - Packet.WriteBEShort(m_Server.GetConnectPort()); - Packet.WriteVarInt(NextState); - AString Pkt; - Packet.ReadAll(Pkt); - cByteBuffer ToServer(512); - ToServer.WriteVarUTF8String(Pkt); - SERVERSEND(ToServer); - - m_ProtocolState = (int)NextState; - - return true; -} - - - - - bool cConnection::HandleClientKeepAlive(void) { HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, ID); @@ -1067,11 +1061,12 @@ bool cConnection::HandleClientKeepAlive(void) bool cConnection::HandleClientLocaleAndView(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Locale); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, ViewDistance); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, ChatFlags); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, Difficulty); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, ShowCape); + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Locale); + HANDLE_CLIENT_PACKET_READ(ReadChar, char, ViewDistance); + HANDLE_CLIENT_PACKET_READ(ReadChar, char, ChatFlags); + HANDLE_CLIENT_PACKET_READ(ReadChar, char, Unused); + HANDLE_CLIENT_PACKET_READ(ReadChar, char, Difficulty); + HANDLE_CLIENT_PACKET_READ(ReadChar, char, ShowCape); Log("Received a PACKET_LOCALE_AND_VIEW from the client"); COPY_TO_SERVER(); return true; @@ -1096,7 +1091,7 @@ bool cConnection::HandleClientPing(void) bool cConnection::HandleClientPlayerAbilities(void) { - HANDLE_CLIENT_PACKET_READ(ReadChar, char, Flags); + HANDLE_CLIENT_PACKET_READ(ReadChar, char, Flags); HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, FlyingSpeed); HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, WalkingSpeed); Log("Receives a PACKET_PLAYER_ABILITIES from the client:"); @@ -1127,7 +1122,7 @@ bool cConnection::HandleClientPlayerLook(void) bool cConnection::HandleClientPlayerOnGround(void) { - HANDLE_CLIENT_PACKET_READ(ReadChar, char, OnGround); + HANDLE_CLIENT_PACKET_READ(ReadChar, char, OnGround); Log("Received a PACKET_PLAYER_ON_GROUND from the client"); COPY_TO_SERVER(); return true; @@ -1140,8 +1135,8 @@ bool cConnection::HandleClientPlayerOnGround(void) bool cConnection::HandleClientPlayerPosition(void) { HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosX); - HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, Stance); HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosY); + HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, Stance); HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosZ); HANDLE_CLIENT_PACKET_READ(ReadChar, char, IsOnGround); Log("Received a PACKET_PLAYER_POSITION from the client"); @@ -1159,8 +1154,8 @@ bool cConnection::HandleClientPlayerPosition(void) bool cConnection::HandleClientPlayerPositionLook(void) { HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosX); - HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, Stance); HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosY); + HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, Stance); HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosZ); HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, Yaw); HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, Pitch); @@ -1168,7 +1163,7 @@ bool cConnection::HandleClientPlayerPositionLook(void) Log("Received a PACKET_PLAYER_POSITION_LOOK from the client"); Log(" Pos = {%.03f, %.03f, %.03f}", PosX, PosY, PosZ); Log(" Stance = %.03f", Stance); - Log(" Y, P = %.03f, %.03f", Yaw, Pitch); + Log(" Yaw, Pitch = <%.03f, %.03f>", Yaw, Pitch); Log(" IsOnGround = %s", IsOnGround ? "true" : "false"); COPY_TO_SERVER(); @@ -1181,7 +1176,7 @@ bool cConnection::HandleClientPlayerPositionLook(void) bool cConnection::HandleClientPluginMessage(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, ChannelName); + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ChannelName); HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, Length); AString Data; if (!m_ClientBuffer.ReadString(Data, Length)) @@ -1238,7 +1233,7 @@ bool cConnection::HandleClientStatusRequest(void) bool cConnection::HandleClientTabCompletion(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Query); + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Query); Log("Received a PACKET_TAB_COMPLETION query from the client"); Log(" Query = \"%s\"", Query.c_str()); COPY_TO_SERVER(); @@ -1251,13 +1246,13 @@ bool cConnection::HandleClientTabCompletion(void) bool cConnection::HandleClientUpdateSign(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, BlockY); - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockZ); - HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Line1); - HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Line2); - HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Line3); - HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Line4); + HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockX); + HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, BlockY); + HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockZ); + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Line1); + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Line2); + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Line3); + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Line4); Log("Received a PACKET_UPDATE_SIGN from the client:"); Log(" Block = {%d, %d, %d}", BlockX, BlockY, BlockZ); Log(" Lines = \"%s\", \"%s\", \"%s\", \"%s\"", Line1.c_str(), Line2.c_str(), Line3.c_str(), Line4.c_str()); @@ -1271,11 +1266,9 @@ bool cConnection::HandleClientUpdateSign(void) bool cConnection::HandleClientUseEntity(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, PlayerID); HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, EntityID); HANDLE_CLIENT_PACKET_READ(ReadChar, char, MouseButton); Log("Received a PACKET_USE_ENTITY from the client:"); - Log(" PlayerID = %d", PlayerID); Log(" EntityID = %d", EntityID); Log(" MouseButton = %d", MouseButton); COPY_TO_SERVER(); @@ -1290,9 +1283,9 @@ bool cConnection::HandleClientWindowClick(void) { HANDLE_CLIENT_PACKET_READ(ReadChar, char, WindowID); HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, SlotNum); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, IsRightClick); + HANDLE_CLIENT_PACKET_READ(ReadChar, char, Button); HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, TransactionID); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, IsShiftClick); + HANDLE_CLIENT_PACKET_READ(ReadChar, char, Mode); AString Item; if (!ParseSlot(m_ClientBuffer, Item)) { @@ -1301,7 +1294,7 @@ bool cConnection::HandleClientWindowClick(void) Log("Received a PACKET_WINDOW_CLICK from the client"); Log(" WindowID = %d", WindowID); Log(" SlotNum = %d", SlotNum); - Log(" IsRclk = %d, IsShift = %d", IsRightClick, IsShiftClick); + Log(" Button = %d, Mode = %d", Button, Mode); Log(" TransactionID = 0x%x", TransactionID); Log(" ClickedItem = %s", Item.c_str()); COPY_TO_SERVER(); @@ -1325,6 +1318,100 @@ bool cConnection::HandleClientWindowClose(void) +bool cConnection::HandleClientUnknownPacket(UInt32 a_PacketType, UInt32 a_PacketLen, UInt32 a_PacketReadSoFar) +{ + AString Data; + if (!m_ClientBuffer.ReadString(Data, a_PacketLen - a_PacketReadSoFar)) + { + return false; + } + DataLog(Data.data(), Data.size(), "****************** Unknown packet 0x%x from the client; relaying and ignoring", a_PacketType); + COPY_TO_SERVER(); + return true; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// packet handling, server-side, login: + +bool cConnection::HandleServerLoginDisconnect(void) +{ + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Reason); + Log("Received a login-disconnect packet from the server:"); + Log(" Reason = \"%s\"", Reason.c_str()); + COPY_TO_SERVER(); + return true; +} + + + + + +bool cConnection::HandleServerLoginEncryptionKeyRequest(void) +{ + // Read the packet from the server: + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ServerID); + HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PublicKeyLength); + AString PublicKey; + if (!m_ServerBuffer.ReadString(PublicKey, PublicKeyLength)) + { + return false; + } + HANDLE_SERVER_PACKET_READ(ReadBEShort, short, NonceLength); + AString Nonce; + if (!m_ServerBuffer.ReadString(Nonce, NonceLength)) + { + return false; + } + Log("Got PACKET_ENCRYPTION_KEY_REQUEST from the SERVER:"); + Log(" ServerID = %s", ServerID.c_str()); + + // Reply to the server: + SendEncryptionKeyResponse(PublicKey, Nonce); + + // Do not send to client - we want the client connection open + return true; +} + + + + + +bool cConnection::HandleServerLoginSuccess(void) +{ + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, UUID); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Username); + Log("Received a login success packet from the server:"); + Log(" UUID = \"%s\"", UUID.c_str()); + Log(" Username = \"%s\"", Username.c_str()); + + Log("Server is now in protocol state Game."); + m_ServerProtocolState = 3; + + if (m_IsServerEncrypted) + { + Log("Server communication is now encrypted"); + m_ServerState = csEncryptedUnderstood; + DataLog(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size(), "Sending the queued data to server (%u bytes):", m_ServerEncryptionBuffer.size()); + SERVERENCRYPTSEND(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size()); + m_ServerEncryptionBuffer.clear(); + } + COPY_TO_CLIENT(); + Log("Client is now in protocol state Game."); + m_ClientProtocolState = 3; + return true; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// packet handling, server-side, game: + bool cConnection::HandleServerAttachEntity(void) { HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); @@ -1344,16 +1431,16 @@ bool cConnection::HandleServerAttachEntity(void) bool cConnection::HandleServerBlockAction(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Byte1); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Byte2); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockID); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX); + HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Byte1); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Byte2); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, BlockID); Log("Received a PACKET_BLOCK_ACTION from the server:"); Log(" Pos = {%d, %d, %d}", BlockX, BlockY, BlockZ); Log(" Bytes = (%d, %d) == (0x%x, 0x%x)", Byte1, Byte2, Byte1, Byte2); - Log(" BlockID = %d", BlockID); + Log(" BlockID = %u", BlockID); COPY_TO_CLIENT(); return true; } @@ -1364,11 +1451,11 @@ bool cConnection::HandleServerBlockAction(void) bool cConnection::HandleServerBlockChange(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, BlockY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockType); - HANDLE_SERVER_PACKET_READ(ReadChar, char, BlockMeta); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, BlockY); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, BlockType); + HANDLE_SERVER_PACKET_READ(ReadChar, char, BlockMeta); Log("Received a PACKET_BLOCK_CHANGE from the server"); COPY_TO_CLIENT(); return true; @@ -1395,7 +1482,7 @@ bool cConnection::HandleServerChangeGameState(void) bool cConnection::HandleServerChatMessage(void) { - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Message); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Message); Log("Received a PACKET_CHAT_MESSAGE from the server:"); Log(" Message = \"%s\"", Message.c_str()); COPY_TO_CLIENT(); @@ -1453,48 +1540,6 @@ bool cConnection::HandleServerDestroyEntities(void) -bool cConnection::HandleServerEncryptionKeyRequest(void) -{ - // Read the packet from the server: - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, ServerID); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PublicKeyLength); - AString PublicKey; - if (!m_ServerBuffer.ReadString(PublicKey, PublicKeyLength)) - { - return false; - } - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, NonceLength); - AString Nonce; - if (!m_ServerBuffer.ReadString(Nonce, NonceLength)) - { - return false; - } - Log("Got PACKET_ENCRYPTION_KEY_REQUEST from the SERVER:"); - Log(" ServerID = %s", ServerID.c_str()); - - // Reply to the server: - SendEncryptionKeyResponse(PublicKey, Nonce); - - // Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#0xFD to the client, using our own key: - Log("Sending PACKET_ENCRYPTION_KEY_REQUEST to the CLIENT"); - AString key; - StringSink sink(key); // GCC won't allow inline instantiation in the following line, damned temporary refs - m_Server.GetPublicKey().Save(sink); - cByteBuffer ToClient(512); - ToClient.WriteByte (PACKET_ENCRYPTION_KEY_REQUEST); - ToClient.WriteBEUTF16String16(ServerID); - ToClient.WriteBEShort ((short)key.size()); - ToClient.WriteBuf (key.data(), key.size()); - ToClient.WriteBEShort (4); - ToClient.WriteBEInt (m_Nonce); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) - CLIENTSEND(ToClient); - return true; -} - - - - - bool cConnection::HandleServerEntity(void) { HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); @@ -1593,20 +1638,18 @@ bool cConnection::HandleServerEntityProperties(void) for (int i = 0; i < Count; i++) { - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Key); - HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, Value); - Log(" \"%s\" = %f", Key.c_str(), Value); - } // for i - - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, ListLength); - Log(" ListLength = %d", ListLength); - for (int i = 0; i < ListLength; i++) - { - HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, UUIDHi); - HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, UUIDLo); - HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, DblVal); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, ByteVal); - Log(" [%d] = {0x%08llx%08llx, %f, %i}", i, UUIDHi, UUIDLo, DblVal, ByteVal); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Key); + HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, Value); + HANDLE_SERVER_PACKET_READ(ReadBEShort, short, ListLength); + Log(" \"%s\" = %f; %d modifiers", Key.c_str(), Value, ListLength); + for (short j = 0; j < ListLength; j++) + { + HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, UUIDHi); + HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, UUIDLo); + HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, DblVal); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, ByteVal); + Log(" [%d] = {0x%08llx%08llx, %f, %u}", j, UUIDHi, UUIDLo, DblVal, ByteVal); + } } // for i COPY_TO_CLIENT(); return true; @@ -1671,7 +1714,7 @@ bool cConnection::HandleServerEntityStatus(void) bool cConnection::HandleServerEntityTeleport(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsX); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsY); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsZ); @@ -1679,7 +1722,7 @@ bool cConnection::HandleServerEntityTeleport(void) HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); Log("Received a PACKET_ENTITY_TELEPORT from the server:"); Log(" EntityID = %d", EntityID); - Log(" Pos = (%d, %d, %d) ~ {%.02f, %.02f, %.02f}", AbsX, AbsY, AbsZ, (double)AbsX / 32, (double)AbsY / 32, (double)AbsZ / 32); + Log(" Pos = %s", PrintableAbsIntTriplet(AbsX, AbsY, AbsZ).c_str()); Log(" Yaw = %d", Yaw); Log(" Pitch = %d", Pitch); COPY_TO_CLIENT(); @@ -1709,11 +1752,11 @@ bool cConnection::HandleServerEntityVelocity(void) bool cConnection::HandleServerExplosion(void) { - HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosZ); - HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Force); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, NumRecords); + HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Force); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, NumRecords); struct sCoords { int x, y, z; @@ -1766,12 +1809,22 @@ bool cConnection::HandleServerIncrementStatistic(void) -bool cConnection::HandleServerKeepAlive(void) +bool cConnection::HandleServerJoinGame(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PingID); - Log("Received a PACKET_KEEP_ALIVE from the server:"); - Log(" ID = %d", PingID); - COPY_TO_CLIENT() + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); + HANDLE_SERVER_PACKET_READ(ReadChar, char, GameMode); + HANDLE_SERVER_PACKET_READ(ReadChar, char, Dimension); + HANDLE_SERVER_PACKET_READ(ReadChar, char, Difficulty); + HANDLE_SERVER_PACKET_READ(ReadChar, char, MaxPlayers); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, LevelType); + Log("Received a PACKET_LOGIN from the server:"); + Log(" EntityID = %d", EntityID); + Log(" GameMode = %d", GameMode); + Log(" Dimension = %d", Dimension); + Log(" Difficulty = %d", Difficulty); + Log(" MaxPlayers = %d", MaxPlayers); + Log(" LevelType = \"%s\"", LevelType.c_str()); + COPY_TO_CLIENT(); return true; } @@ -1779,19 +1832,12 @@ bool cConnection::HandleServerKeepAlive(void) -bool cConnection::HandleServerEncryptionKeyResponse(void) +bool cConnection::HandleServerKeepAlive(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Lengths); - if (Lengths != 0) - { - Log("Lengths are not zero!"); - return true; - } - Log("Server communication is now encrypted"); - m_ServerState = csEncryptedUnderstood; - DataLog(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size(), "Sending the queued data to server (%u bytes):", m_ServerEncryptionBuffer.size()); - SERVERENCRYPTSEND(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size()); - m_ServerEncryptionBuffer.clear(); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PingID); + Log("Received a PACKET_KEEP_ALIVE from the server:"); + Log(" ID = %d", PingID); + COPY_TO_CLIENT() return true; } @@ -1801,7 +1847,7 @@ bool cConnection::HandleServerEncryptionKeyResponse(void) bool cConnection::HandleServerKick(void) { - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Reason); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Reason); Log("Received PACKET_KICK from the SERVER:"); if (m_HasClientPinged) { @@ -1871,31 +1917,6 @@ bool cConnection::HandleServerKick(void) -bool cConnection::HandleServerLogin(void) -{ - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, LevelType); - HANDLE_SERVER_PACKET_READ(ReadChar, char, GameMode); - HANDLE_SERVER_PACKET_READ(ReadChar, char, Dimension); - HANDLE_SERVER_PACKET_READ(ReadChar, char, Difficulty); - HANDLE_SERVER_PACKET_READ(ReadChar, char, Unused); - HANDLE_SERVER_PACKET_READ(ReadChar, char, MaxPlayers); - Log("Received a PACKET_LOGIN from the server:"); - Log(" EntityID = %d", EntityID); - Log(" LevelType = \"%s\"", LevelType.c_str()); - Log(" GameMode = %d", GameMode); - Log(" Dimension = %d", Dimension); - Log(" Difficulty = %d", Difficulty); - Log(" Unused = %d", Unused); - Log(" MaxPlayers = %d", MaxPlayers); - COPY_TO_CLIENT(); - return true; -} - - - - - bool cConnection::HandleServerMapChunk(void) { HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX); @@ -2006,15 +2027,15 @@ bool cConnection::HandleServerMultiBlockChange(void) bool cConnection::HandleServerNamedSoundEffect(void) { - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, SoundName); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Volume); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, SoundName); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Volume); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); Log("Received a PACKET_NAMED_SOUND_EFFECT from the server:"); Log(" SoundName = \"%s\"", SoundName.c_str()); - Log(" Pos = (%d, %d, %d) ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 8, PosY / 8, PosZ / 8); + Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ, 8).c_str()); Log(" Volume = %f", Volume); Log(" Pitch = %d", Pitch); COPY_TO_CLIENT(); @@ -2044,10 +2065,10 @@ bool cConnection::HandleServerPlayerAbilities(void) bool cConnection::HandleServerPlayerAnimation(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PlayerID); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, AnimationID); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, PlayerID); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, AnimationID); Log("Received a PACKET_PLAYER_ANIMATION from the server:"); - Log(" PlayerID: %d (0x%x)", PlayerID, PlayerID); + Log(" PlayerID: %u (0x%x)", PlayerID, PlayerID); Log(" Animation: %d", AnimationID); COPY_TO_CLIENT(); return true; @@ -2059,7 +2080,7 @@ bool cConnection::HandleServerPlayerAnimation(void) bool cConnection::HandleServerPlayerListItem(void) { - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, PlayerName); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, PlayerName); HANDLE_SERVER_PACKET_READ(ReadChar, char, IsOnline); HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Ping); Log("Received a PACKET_PLAYERLIST_ITEM from the server:"); @@ -2076,7 +2097,6 @@ bool cConnection::HandleServerPlayerListItem(void) bool cConnection::HandleServerPlayerPositionLook(void) { HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, Stance); HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosY); HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosZ); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Yaw); @@ -2096,7 +2116,7 @@ bool cConnection::HandleServerPlayerPositionLook(void) bool cConnection::HandleServerPluginMessage(void) { - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, ChannelName); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ChannelName); HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Length); AString Data; if (!m_ServerBuffer.ReadString(Data, Length)) @@ -2106,7 +2126,26 @@ bool cConnection::HandleServerPluginMessage(void) Log("Received a PACKET_PLUGIN_MESSAGE from the server"); Log(" ChannelName = \"%s\"", ChannelName.c_str()); DataLog(Data.data(), Length, " Data: %d bytes", Length); - COPY_TO_SERVER(); + COPY_TO_CLIENT(); + return true; +} + + + + + +bool cConnection::HandleServerRespawn(void) +{ + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Dimension); + HANDLE_SERVER_PACKET_READ(ReadChar, char, Difficulty); + HANDLE_SERVER_PACKET_READ(ReadChar, char, GameMode); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, LevelType); + Log("Received a respawn packet from the server:"); + Log(" Dimension = %d", Dimension); + Log(" Difficulty = %d", Difficulty); + Log(" GameMode = %d", GameMode); + Log(" LevelType = \"%s\"", LevelType.c_str()); + COPY_TO_CLIENT(); return true; } @@ -2154,7 +2193,7 @@ bool cConnection::HandleServerSetSlot(void) bool cConnection::HandleServerSlotSelect(void) { - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, SlotNum); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, SlotNum); Log("Received a PACKET_SLOT_SELECT from the server:"); Log(" SlotNum = %d", SlotNum); COPY_TO_CLIENT(); @@ -2186,6 +2225,25 @@ bool cConnection::HandleServerSoundEffect(void) +bool cConnection::HandleServerSpawnExperienceOrbs(void) +{ + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Count); + Log("Received a SPAWN_EXPERIENCE_ORBS packet from the server:"); + Log(" EntityID = %u (0x%x)", EntityID, EntityID); + Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); + Log(" Count = %d", Count); + COPY_TO_CLIENT(); + return true; +} + + + + + bool cConnection::HandleServerSpawnMob(void) { HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); @@ -2224,14 +2282,15 @@ bool cConnection::HandleServerSpawnMob(void) bool cConnection::HandleServerSpawnNamedEntity(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, EntityName); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, CurrentItem); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityUUID); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityName); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); + HANDLE_SERVER_PACKET_READ(ReadBEShort, short, CurrentItem); AString Metadata; if (!ParseMetadata(m_ServerBuffer, Metadata)) { @@ -2240,7 +2299,8 @@ bool cConnection::HandleServerSpawnNamedEntity(void) AString HexDump; CreateHexDump(HexDump, Metadata.data(), Metadata.size(), 32); Log("Received a PACKET_SPAWN_NAMED_ENTITY from the server:"); - Log(" EntityID = %d (0x%x)", EntityID, EntityID); + Log(" EntityID = %u (0x%x)", EntityID, EntityID); + Log(" UUID = %s", EntityUUID.c_str()); Log(" Name = %s", EntityName.c_str()); Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch); @@ -2273,14 +2333,14 @@ bool cConnection::HandleServerSpawnObjectVehicle(void) DataLog(Buffer.data(), Buffer.size(), "Buffer while parsing the PACKET_SPAWN_OBJECT_VEHICLE packet (%d bytes):", Buffer.size()); #endif // _DEBUG - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadChar, char, ObjType); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, DataIndicator); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, ObjType); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, DataIndicator); AString ExtraData; short VelocityX, VelocityY, VelocityZ; if (DataIndicator != 0) @@ -2313,7 +2373,7 @@ bool cConnection::HandleServerSpawnObjectVehicle(void) */ } Log("Received a PACKET_SPAWN_OBJECT_VEHICLE from the server:"); - Log(" EntityID = %d (0x%x)", EntityID, EntityID); + Log(" EntityID = %u (0x%x)", EntityID, EntityID); Log(" ObjType = %d (0x%x)", ObjType, ObjType); Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch); @@ -2333,14 +2393,14 @@ bool cConnection::HandleServerSpawnObjectVehicle(void) bool cConnection::HandleServerSpawnPainting(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, ImageName); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Direction); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ImageName); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Direction); Log("Received a PACKET_SPAWN_PAINTING from the server:"); - Log(" EntityID = %d", EntityID); + Log(" EntityID = %u", EntityID); Log(" ImageName = \"%s\"", ImageName.c_str()); Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); Log(" Direction = %d", Direction); @@ -2379,6 +2439,21 @@ bool cConnection::HandleServerSpawnPickup(void) +bool cConnection::HandleServerStatistics(void) +{ + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, NumEntries); + for (UInt32 i = 0; i < NumEntries; i++) + { + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, StatName); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, StatValue); + } + COPY_TO_CLIENT(); + return true; +} + + + + bool cConnection::HandleServerStatusPing(void) { HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, Time); @@ -2421,7 +2496,8 @@ bool cConnection::HandleServerStatusResponse(void) bool cConnection::HandleServerTabCompletion(void) { - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Results); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, NumResults); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Results); Log("Received a PACKET_TAB_COMPLETION from the server, results given:"); // Parse the zero-terminated list of results: @@ -2479,10 +2555,10 @@ bool cConnection::HandleServerUpdateSign(void) HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX); HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ); - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Line1); - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Line2); - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Line3); - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Line4); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Line1); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Line2); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Line3); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Line4); Log("Received a PACKET_UPDATE_SIGN from the server:"); Log(" Block = {%d, %d, %d}", BlockX, BlockY, BlockZ); Log(" Lines = \"%s\", \"%s\", \"%s\", \"%s\"", Line1.c_str(), Line2.c_str(), Line3.c_str(), Line4.c_str()); @@ -2509,7 +2585,24 @@ bool cConnection::HandleServerUpdateTileEntity(void) Log("Received a PACKET_UPDATE_TILE_ENTITY from the server:"); Log(" Block = {%d, %d, %d}", BlockX, BlockY, BlockZ); Log(" Action = %d", Action); - DataLog(Data.data(), Data.size(), " Data (%d bytes)", Data.size()); + DataLog(Data.data(), Data.size(), " Data (%u bytes)", Data.size()); + COPY_TO_CLIENT(); + return true; +} + + + + + +bool cConnection::HandleServerUseBed(void) +{ + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BedX); + HANDLE_SERVER_PACKET_READ(ReadByte, Byte, BedY); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BedZ); + Log("Received a use bed packet from the server:"); + Log(" EntityID = %d", EntityID); + Log(" Bed = {%d, %d, %d}", BedX, BedY, BedZ); COPY_TO_CLIENT(); return true; } @@ -2561,14 +2654,14 @@ bool cConnection::HandleServerWindowOpen(void) { HANDLE_SERVER_PACKET_READ(ReadChar, char, WindowID); HANDLE_SERVER_PACKET_READ(ReadChar, char, WindowType); - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Title); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Title); HANDLE_SERVER_PACKET_READ(ReadByte, Byte, NumSlots); HANDLE_SERVER_PACKET_READ(ReadByte, Byte, UseProvidedTitle); - int HorseInt = 0; + int HorseEntityID = 0; if (WindowType == 11) // Horse / Donkey / Mule { HANDLE_SERVER_PACKET_READ(ReadBEInt, int, intHorseInt); - HorseInt = intHorseInt; + HorseEntityID = intHorseInt; } Log("Received a PACKET_WINDOW_OPEN from the server:"); Log(" WindowID = %d", WindowID); @@ -2577,8 +2670,24 @@ bool cConnection::HandleServerWindowOpen(void) Log(" NumSlots = %d", NumSlots); if (WindowType == 11) { - Log(" HorseInt = %d (0x%08x)", HorseInt, HorseInt); + Log(" HorseEntityID = %d (0x%08x)", HorseEntityID, HorseEntityID); + } + COPY_TO_CLIENT(); + return true; +} + + + + + +bool cConnection::HandleServerUnknownPacket(UInt32 a_PacketType, UInt32 a_PacketLen, UInt32 a_PacketReadSoFar) +{ + AString Data; + if (!m_ServerBuffer.ReadString(Data, a_PacketLen - a_PacketReadSoFar)) + { + return false; } + DataLog(Data.data(), Data.size(), "****************** Unknown packet 0x%x from the server; relaying and ignoring", a_PacketType); COPY_TO_CLIENT(); return true; } @@ -2826,68 +2935,14 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c // Send the packet to the server: Log("Sending PACKET_ENCRYPTION_KEY_RESPONSE to the SERVER"); cByteBuffer ToServer(1024); - ToServer.WriteByte(PACKET_ENCRYPTION_KEY_RESPONSE); + ToServer.WriteByte(0x01); // To server: Encryption key response ToServer.WriteBEShort(EncryptedLength); ToServer.WriteBuf(EncryptedSecret, EncryptedLength); ToServer.WriteBEShort(EncryptedLength); ToServer.WriteBuf(EncryptedNonce, EncryptedLength); SERVERSEND(ToServer); - m_ServerState = csWaitingForEncryption; -} - - - - - -void cConnection::StartClientEncryption(const AString & a_EncKey, const AString & a_EncNonce) -{ - // Decrypt EncNonce using privkey - RSAES<PKCS1v15>::Decryptor rsaDecryptor(m_Server.GetPrivateKey()); - time_t CurTime = time(NULL); - RandomPool rng; - rng.Put((const byte *)&CurTime, sizeof(CurTime)); - byte DecryptedNonce[MAX_ENC_LEN]; - DecodingResult res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncNonce.data(), a_EncNonce.size(), DecryptedNonce); - if (!res.isValidCoding || (res.messageLength != 4)) - { - Log("Client: Bad nonce length"); - return; - } - if (ntohl(*((int *)DecryptedNonce)) != m_Nonce) - { - Log("Bad nonce value"); - return; - } - - // Decrypt the symmetric encryption key using privkey: - byte SharedSecret[MAX_ENC_LEN]; - res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncKey.data(), a_EncKey.size(), SharedSecret); - if (!res.isValidCoding || (res.messageLength != 16)) - { - Log("Bad key length"); - return; - } - - // Send encryption key response: - cByteBuffer ToClient(6); - ToClient.WriteByte((char)0xfc); - ToClient.WriteBEShort(0); - ToClient.WriteBEShort(0); - CLIENTSEND(ToClient); - - // Start the encryption: - m_ClientEncryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16))(Name::FeedbackSize(), 1)); - m_ClientDecryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16))(Name::FeedbackSize(), 1)); - Log("Client connection is now encrypted"); - m_ClientState = csEncryptedUnderstood; - - // Send the queued data: - DataLog(m_ClientEncryptionBuffer.data(), m_ClientEncryptionBuffer.size(), "Sending the queued data to client (%u bytes):", m_ClientEncryptionBuffer.size()); - CLIENTENCRYPTSEND(m_ClientEncryptionBuffer.data(), m_ClientEncryptionBuffer.size()); - m_ClientEncryptionBuffer.clear(); - - // Handle all postponed server data - DecodeServersPackets(NULL, 0); + m_ServerState = csEncryptedUnderstood; + m_IsServerEncrypted = true; } diff --git a/Tools/ProtoProxy/Connection.h b/Tools/ProtoProxy/Connection.h index d1006c95a..c2bce30fb 100644 --- a/Tools/ProtoProxy/Connection.h +++ b/Tools/ProtoProxy/Connection.h @@ -71,17 +71,27 @@ protected: Decryptor m_ServerDecryptor; Encryptor m_ServerEncryptor; - Decryptor m_ClientDecryptor; - Encryptor m_ClientEncryptor; - - AString m_ClientEncryptionBuffer; // Buffer for the data to be sent to the client once encryption is established AString m_ServerEncryptionBuffer; // Buffer for the data to be sent to the server once encryption is established /// Set to true when PACKET_PING is received from the client; will cause special parsing for server kick bool m_HasClientPinged; - /// State the protocol is in (as defined by the initial handshake), -1 if no initial handshake received yet - int m_ProtocolState; + /* + The protocol states can be one of: + -1: no initial handshake received yet + 1: status + 2: login + 3: game + */ + /// State the to-server protocol is in (as defined by the initial handshake / login), -1 if no initial handshake received yet + int m_ServerProtocolState; + + /// State the to-client protocol is in (as defined by the initial handshake / login), -1 if no initial handshake received yet + int m_ClientProtocolState; + + /// True if the server connection has provided encryption keys + bool m_IsServerEncrypted; + bool ConnectToServer(void); @@ -112,7 +122,18 @@ protected: /// Decodes packets coming from the server, sends appropriate counterparts to the client; returns false if the connection is to be dropped bool DecodeServersPackets(const char * a_Data, int a_Size); - // Packet handling, client-side: + // Packet handling, client-side, initial: + bool HandleClientHandshake(void); + + // Packet handling, client-side, status: + bool HandleClientStatusPing(void); + bool HandleClientStatusRequest(void); + + // Packet handling, client-side, login: + bool HandleClientLoginEncryptionKeyResponse(void); + bool HandleClientLoginStart(void); + + // Packet handling, client-side, game: bool HandleClientAnimation(void); bool HandleClientBlockDig(void); bool HandleClientBlockPlace(void); @@ -120,9 +141,7 @@ protected: bool HandleClientClientStatuses(void); bool HandleClientCreativeInventoryAction(void); bool HandleClientDisconnect(void); - bool HandleClientEncryptionKeyResponse(void); bool HandleClientEntityAction(void); - bool HandleClientHandshake(void); bool HandleClientKeepAlive(void); bool HandleClientLocaleAndView(void); bool HandleClientPing(void); @@ -133,15 +152,20 @@ protected: bool HandleClientPlayerPositionLook(void); bool HandleClientPluginMessage(void); bool HandleClientSlotSelect(void); - bool HandleClientStatusPing(void); - bool HandleClientStatusRequest(void); bool HandleClientTabCompletion(void); bool HandleClientUpdateSign(void); bool HandleClientUseEntity(void); bool HandleClientWindowClick(void); bool HandleClientWindowClose(void); + + bool HandleClientUnknownPacket(UInt32 a_PacketType, UInt32 a_PacketLen, UInt32 a_PacketReadSoFar); - // Packet handling, server-side: + // Packet handling, server-side, login: + bool HandleServerLoginDisconnect(void); + bool HandleServerLoginEncryptionKeyRequest(void); + bool HandleServerLoginSuccess(void); + + // Packet handling, server-side, game: bool HandleServerAttachEntity(void); bool HandleServerBlockAction(void); bool HandleServerBlockChange(void); @@ -150,8 +174,6 @@ protected: bool HandleServerCollectPickup(void); bool HandleServerCompass(void); bool HandleServerDestroyEntities(void); - bool HandleServerEncryptionKeyRequest(void); - bool HandleServerEncryptionKeyResponse(void); bool HandleServerEntity(void); bool HandleServerEntityEquipment(void); bool HandleServerEntityHeadLook(void); @@ -165,6 +187,7 @@ protected: bool HandleServerEntityVelocity(void); bool HandleServerExplosion(void); bool HandleServerIncrementStatistic(void); + bool HandleServerJoinGame(void); bool HandleServerKeepAlive(void); bool HandleServerKick(void); bool HandleServerLogin(void); @@ -177,15 +200,18 @@ protected: bool HandleServerPlayerListItem(void); bool HandleServerPlayerPositionLook(void); bool HandleServerPluginMessage(void); + bool HandleServerRespawn(void); bool HandleServerSetExperience(void); bool HandleServerSetSlot(void); bool HandleServerSlotSelect(void); bool HandleServerSoundEffect(void); + bool HandleServerSpawnExperienceOrbs(void); bool HandleServerSpawnMob(void); bool HandleServerSpawnNamedEntity(void); bool HandleServerSpawnObjectVehicle(void); bool HandleServerSpawnPainting(void); bool HandleServerSpawnPickup(void); + bool HandleServerStatistics(void); bool HandleServerStatusPing(void); bool HandleServerStatusResponse(void); bool HandleServerTabCompletion(void); @@ -193,10 +219,13 @@ protected: bool HandleServerUpdateHealth(void); bool HandleServerUpdateSign(void); bool HandleServerUpdateTileEntity(void); + bool HandleServerUseBed(void); bool HandleServerWindowClose(void); bool HandleServerWindowContents(void); bool HandleServerWindowOpen(void); + bool HandleServerUnknownPacket(UInt32 a_PacketType, UInt32 a_PacketLen, UInt32 a_PacketReadSoFar); + /// Parses the slot data in a_Buffer into item description; returns true if successful, false if not enough data bool ParseSlot(cByteBuffer & a_Buffer, AString & a_ItemDesc); diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index 8c432280f..cb8cf9f81 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -2528,6 +2528,14 @@ > </File> <File + RelativePath="..\source\Protocol\Protocol17x.cpp" + > + </File> + <File + RelativePath="..\source\Protocol\Protocol17x.h" + > + </File> + <File RelativePath="..\source\Protocol\ProtocolRecognizer.cpp" > </File> diff --git a/source/Blocks/BlockDirt.h b/source/Blocks/BlockDirt.h index b2bc4756c..c694d79f6 100644 --- a/source/Blocks/BlockDirt.h +++ b/source/Blocks/BlockDirt.h @@ -37,7 +37,7 @@ public: if (a_BlockY < cChunkDef::Height - 1) { BLOCKTYPE Above = a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); - if (!g_BlockTransparent[Above] && !g_BlockOneHitDig[Above]) + if ((!g_BlockTransparent[Above] && !g_BlockOneHitDig[Above]) || IsBlockWater(Above)) { a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DIRT, 0); return; @@ -69,7 +69,7 @@ public: NIBBLETYPE AboveMeta; IsValid = a_World->GetBlockTypeMeta(a_BlockX + OfsX, a_BlockY + OfsY + 1, a_BlockZ + OfsZ, AboveDest, AboveMeta); ASSERT(IsValid); // WTF - how did we get the DestBlock if AboveBlock is not valid? - if (g_BlockOneHitDig[AboveDest] || g_BlockTransparent[AboveDest]) + if ((g_BlockOneHitDig[AboveDest] || g_BlockTransparent[AboveDest]) && !IsBlockWater(AboveDest)) { a_World->FastSetBlock(a_BlockX + OfsX, a_BlockY + OfsY, a_BlockZ + OfsZ, E_BLOCK_GRASS, 0); } diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index 90802aa71..ea8b48f9d 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -469,7 +469,7 @@ bool cClientHandle::HandleLogin(int a_ProtocolVersion, const AString & a_Usernam void cClientHandle::HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem) { // This is for creative Inventory changes - if (m_Player->IsGameModeCreative()) + if (!m_Player->IsGameModeCreative()) { LOGWARNING("Got a CreativeInventoryAction packet from user \"%s\" while not in creative mode. Ignoring.", m_Username.c_str()); return; @@ -650,7 +650,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc m_LastDigBlockZ = a_BlockZ; if ( - (m_Player->GetGameMode() == eGameMode_Creative) || // In creative mode, digging is done immediately + (m_Player->IsGameModeCreative()) || // In creative mode, digging is done immediately g_BlockOneHitDig[a_OldBlock] // One-hit blocks get destroyed immediately, too ) { diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 4c8e680d0..1d5532718 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -474,8 +474,17 @@ cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { - // TODO: Random-spawn a chicken or four - + if (m_World->GetTickRandomNumber(7) == 1) + { + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + } + else if (m_World->GetTickRandomNumber(32) == 1) + { + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + } Destroy(); } diff --git a/source/Mobs/AggressiveMonster.cpp b/source/Mobs/AggressiveMonster.cpp index ee6252656..88bd2743a 100644 --- a/source/Mobs/AggressiveMonster.cpp +++ b/source/Mobs/AggressiveMonster.cpp @@ -33,7 +33,7 @@ void cAggressiveMonster::InStateChasing(float a_Dt) if (m_Target->IsPlayer()) { cPlayer * Player = (cPlayer *) m_Target; - if (Player->GetGameMode() == 1) + if (Player->IsGameModeCreative()) { m_EMState = IDLE; return; diff --git a/source/Mobs/Horse.cpp b/source/Mobs/Horse.cpp index f9705a451..d18887ea4 100644 --- a/source/Mobs/Horse.cpp +++ b/source/Mobs/Horse.cpp @@ -1,4 +1,3 @@ - #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Horse.h" @@ -142,6 +141,10 @@ void cHorse::OnRightClicked(cPlayer & a_Player) void cHorse::GetDrops(cItems & a_Drops, cEntity * a_Killer) { AddRandomDropItem(a_Drops, 0, 2, E_ITEM_LEATHER); + if (m_bIsSaddled) + { + a_Drops.push_back(cItem(E_ITEM_SADDLE, 1)); + } } diff --git a/source/Mobs/Pig.cpp b/source/Mobs/Pig.cpp index 5427cf35f..0871a38a9 100644 --- a/source/Mobs/Pig.cpp +++ b/source/Mobs/Pig.cpp @@ -22,6 +22,10 @@ cPig::cPig(void) : void cPig::GetDrops(cItems & a_Drops, cEntity * a_Killer) { AddRandomDropItem(a_Drops, 1, 3, IsOnFire() ? E_ITEM_COOKED_PORKCHOP : E_ITEM_RAW_PORKCHOP); + if (m_bIsSaddled) + { + a_Drops.push_back(cItem(E_ITEM_SADDLE, 1)); + } } diff --git a/source/Protocol/Protocol.h b/source/Protocol/Protocol.h index 5071f5961..466cf874b 100644 --- a/source/Protocol/Protocol.h +++ b/source/Protocol/Protocol.h @@ -186,6 +186,27 @@ protected: WriteInt(a_Vector.y); WriteInt(a_Vector.z); } + + void WriteVarInt(UInt32 a_Value) + { + // A 32-bit integer can be encoded by at most 5 bytes: + unsigned char b[5]; + int idx = 0; + do + { + b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00); + a_Value = a_Value >> 7; + idx++; + } while (a_Value > 0); + + SendData((const char *)b, idx); + } + + void WriteVarUTF8String(const AString & a_String) + { + WriteVarInt(a_String.size()); + SendData(a_String.data(), a_String.size()); + } } ; diff --git a/source/Protocol/Protocol125.h b/source/Protocol/Protocol125.h index ae198780c..da3f81444 100644 --- a/source/Protocol/Protocol125.h +++ b/source/Protocol/Protocol125.h @@ -92,9 +92,9 @@ protected: PARSE_INCOMPLETE = -3, } ; - cByteBuffer m_ReceivedData; //< Buffer for the received data + cByteBuffer m_ReceivedData; ///< Buffer for the received data - AString m_Username; //< Stored in ParseHandshake(), compared to Login username + AString m_Username; ///< Stored in ParseHandshake(), compared to Login username virtual void SendData(const char * a_Data, int a_Size) override; diff --git a/source/Protocol/Protocol17x.cpp b/source/Protocol/Protocol17x.cpp new file mode 100644 index 000000000..b93a95e12 --- /dev/null +++ b/source/Protocol/Protocol17x.cpp @@ -0,0 +1,216 @@ + +// Protocol17x.cpp + +/* +Implements the 1.7.x protocol classes: + - cProtocol172 + - release 1.7.2 protocol (#4) +(others may be added later in the future for the 1.7 release series) +*/ + +#include "Globals.h" +#include "Protocol17x.h" +#include "../ClientHandle.h" +#include "../Root.h" +#include "../Server.h" + + + + + +cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) : + super(a_Client), + m_ServerAddress(a_ServerAddress), + m_ServerPort(a_ServerPort), + m_State(a_State), + m_ReceivedData(32 KiB), + m_IsEncrypted(false) +{ +} + + + + + +void cProtocol172::DataReceived(const char * a_Data, int a_Size) +{ + if (m_IsEncrypted) + { + byte Decrypted[512]; + while (a_Size > 0) + { + int NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size; + m_Decryptor.ProcessData(Decrypted, (byte *)a_Data, NumBytes); + AddReceivedData((const char *)Decrypted, NumBytes); + a_Size -= NumBytes; + a_Data += NumBytes; + } + } + else + { + AddReceivedData(a_Data, a_Size); + } +} + + + + +void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) +{ + if (!m_ReceivedData.Write(a_Data, a_Size)) + { + // Too much data in the incoming queue, report to caller: + m_Client->PacketBufferFull(); + return; + } + + // Handle all complete packets: + while (true) + { + UInt32 PacketLen; + if (!m_ReceivedData.ReadVarInt(PacketLen)) + { + // Not enough data + return; + } + if (!m_ReceivedData.CanReadBytes(PacketLen)) + { + // The full packet hasn't been received yet + return; + } + UInt32 PacketType; + UInt32 NumBytesRead = m_ReceivedData.GetReadableSpace(); + if (!m_ReceivedData.ReadVarInt(PacketType)) + { + // Not enough data + return; + } + NumBytesRead -= m_ReceivedData.GetReadableSpace(); + HandlePacket(PacketType, PacketLen - NumBytesRead); + } // while (true) +} + + + + +void cProtocol172::HandlePacket(UInt32 a_PacketType, UInt32 a_RemainingBytes) +{ + switch (m_State) + { + case 1: + { + // Status + switch (a_PacketType) + { + case 0x00: HandlePacketStatusRequest(a_RemainingBytes); return; + } + break; + } + + case 2: + { + // Login + break; + } + + case 3: + { + // Game + break; + } + } // switch (m_State) + + // Unknown packet type, report to the client: + m_Client->PacketUnknown(a_PacketType); + m_ReceivedData.SkipRead(a_RemainingBytes); + m_ReceivedData.CommitRead(); +} + + + + + +void cProtocol172::HandlePacketStatusRequest(UInt32 a_RemainingBytes) +{ + // No more bytes in this packet + ASSERT(a_RemainingBytes == 0); + m_ReceivedData.CommitRead(); + + // Send the response: + AString Response = "{\"version\":{\"name\":\"1.7.2\",\"protocol\":4},\"players\":{"; + AppendPrintf(Response, "\"max\":%u,\"online\":%u,\"sample\":[]},", + cRoot::Get()->GetServer()->GetMaxPlayers(), + cRoot::Get()->GetServer()->GetNumPlayers() + ); + AppendPrintf(Response, "\"description\":{\"text\":\"%s\"}", + cRoot::Get()->GetServer()->GetDescription().c_str() + ); + Response.append("}"); + + cByteBuffer Packet(Response.size() + 10); + Packet.WriteVarInt(0x00); // Response packet + Packet.WriteVarUTF8String(Response); + WritePacket(Packet); +} + + + + + +void cProtocol172::WritePacket(cByteBuffer & a_Packet) +{ + cCSLock Lock(m_CSPacket); + AString Pkt; + a_Packet.ReadAll(Pkt); + WriteVarInt(Pkt.size()); + SendData(Pkt.data(), Pkt.size()); + Flush(); +} + + + + + +void cProtocol172::SendData(const char * a_Data, int a_Size) +{ + m_DataToSend.append(a_Data, a_Size); +} + + + + + +void cProtocol172::Flush(void) +{ + ASSERT(m_CSPacket.IsLockedByCurrentThread()); // Did all packets lock the CS properly? + + if (m_DataToSend.empty()) + { + LOGD("Flushing empty"); + return; + } + const char * a_Data = m_DataToSend.data(); + int a_Size = m_DataToSend.size(); + if (m_IsEncrypted) + { + byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks) + while (a_Size > 0) + { + int NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size; + m_Encryptor.ProcessData(Encrypted, (byte *)a_Data, NumBytes); + m_Client->SendData((const char *)Encrypted, NumBytes); + a_Size -= NumBytes; + a_Data += NumBytes; + } + } + else + { + m_Client->SendData(a_Data, a_Size); + } + m_DataToSend.clear(); +} + + + + + diff --git a/source/Protocol/Protocol17x.h b/source/Protocol/Protocol17x.h new file mode 100644 index 000000000..cea39f073 --- /dev/null +++ b/source/Protocol/Protocol17x.h @@ -0,0 +1,75 @@ + +// Protocol17x.h + +/* +Declares the 1.7.x protocol classes: + - cProtocol172 + - release 1.7.2 protocol (#4) +(others may be added later in the future for the 1.7 release series) +*/ + + + + + +#pragma once + +#include "Protocol16x.h" + + + + + +class cProtocol172 : + public cProtocol162 // TODO +{ + typedef cProtocol162 super; // TODO + +public: + + cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State); + + /// Called when client sends some data: + virtual void DataReceived(const char * a_Data, int a_Size) override; + +protected: + + AString m_ServerAddress; + + UInt16 m_ServerPort; + + /// State of the protocol. 1 = status, 2 = login + UInt32 m_State; + + /// Buffer for the received data + cByteBuffer m_ReceivedData; + + bool m_IsEncrypted; + CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor; + CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_Encryptor; + + /// (Unencrypted) data to be sent to the client. Written by SendData, cleared by Flush() + AString m_DataToSend; + + + /// Adds the received (unencrypted) data to m_ReceivedData, parses complete packets + void AddReceivedData(const char * a_Data, int a_Size); + + /// Reads and handles the packet. The packet length and type have already been read. + void HandlePacket(UInt32 a_PacketType, UInt32 a_RemainingBytes); + + void HandlePacketStatusRequest(UInt32 a_RemainingBytes); + + /// Writes an entire packet into the output stream. a_Packet is expected to start with the packet type; data length is prepended here. + void WritePacket(cByteBuffer & a_Packet); + + /// Adds unencrypted data to the outgoing data buffer + virtual void SendData(const char * a_Data, int a_Size) override; + + /// Flushes m_DataToSend through the optional encryption into the outgoing socket data + virtual void Flush(void) override; +} ; + + + + diff --git a/source/Protocol/ProtocolRecognizer.cpp b/source/Protocol/ProtocolRecognizer.cpp index ceada1944..18e9186b2 100644 --- a/source/Protocol/ProtocolRecognizer.cpp +++ b/source/Protocol/ProtocolRecognizer.cpp @@ -12,6 +12,7 @@ #include "Protocol14x.h" #include "Protocol15x.h" #include "Protocol16x.h" +#include "Protocol17x.h" #include "../ClientHandle.h" #include "../Root.h" #include "../Server.h" @@ -667,11 +668,65 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void) } switch (PacketType) { - case 0x02: break; // Handshake, continue recognizing - case 0xfe: HandleServerPing(); return false; - default: return false; + case 0x02: return TryRecognizeLengthlessProtocol(); // Handshake, continue recognizing + case 0xfe: + { + // This may be either a packet length or the length-less Ping packet + Byte NextByte; + if (!m_Buffer.ReadByte(NextByte)) + { + // Not enough data for either protocol + // This could actually happen with the 1.2 / 1.3 client, but their support is fading out anyway + return false; + } + if (NextByte != 0x01) + { + // This is definitely NOT a length-less Ping packet, handle as lengthed protocol: + break; + } + if (!m_Buffer.ReadByte(NextByte)) + { + // There is no more data. Although this *could* mean TCP fragmentation, it is highly unlikely + // and rather this is a 1.4 client sending a regular Ping packet (without the following Plugin message) + SendLengthlessServerPing(); + return false; + } + if (NextByte == 0xfa) + { + // Definitely a length-less Ping followed by a Plugin message + SendLengthlessServerPing(); + return false; + } + // Definitely a lengthed Initial handshake, handle below: + break; + } + } // switch (PacketType) + + // This must be a lengthed protocol, try if it has the entire initial handshake packet: + m_Buffer.ResetRead(); + UInt32 PacketLen; + UInt32 ReadSoFar = m_Buffer.GetReadableSpace(); + if (!m_Buffer.ReadVarInt(PacketLen)) + { + // Not enough bytes for the packet length, keep waiting + return false; } - + ReadSoFar -= m_Buffer.GetReadableSpace(); + if (!m_Buffer.CanReadBytes(PacketLen)) + { + // Not enough bytes for the packet, keep waiting + return false; + } + return TryRecognizeLengthedProtocol(PacketLen - ReadSoFar); +} + + + + + +bool cProtocolRecognizer::TryRecognizeLengthlessProtocol(void) +{ + // The comm started with 0x02, which is a Handshake packet in the length-less protocol family // 1.3.2 starts with 0x02 0x39 <name-length-short> // 1.2.5 starts with 0x02 <name-length-short> and name is expected to less than 0x3900 long :) char ch; @@ -724,7 +779,56 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void) -void cProtocolRecognizer::HandleServerPing(void) +bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining) +{ + UInt32 PacketType; + UInt32 NumBytesRead = m_Buffer.GetReadableSpace(); + if (!m_Buffer.ReadVarInt(PacketType)) + { + return false; + } + if (PacketType != 0x00) + { + // Not an initial handshake packet, we don't know how to talk to them + LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, initial packet %u)", + m_Client->GetIPString().c_str(), PacketType + ); + m_Client->Kick("Unsupported protocol version"); + return false; + } + UInt32 ProtocolVersion; + if (!m_Buffer.ReadVarInt(ProtocolVersion)) + { + return false; + } + NumBytesRead -= m_Buffer.GetReadableSpace(); + switch (ProtocolVersion) + { + case PROTO_VERSION_1_7_2: + { + AString ServerAddress; + short ServerPort; + UInt32 NextState; + m_Buffer.ReadVarUTF8String(ServerAddress); + m_Buffer.ReadBEShort(ServerPort); + m_Buffer.ReadVarInt(NextState); + m_Buffer.CommitRead(); + m_Protocol = new cProtocol172(m_Client, ServerAddress, ServerPort, NextState); + return true; + } + } + LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u)", + m_Client->GetIPString().c_str(), ProtocolVersion + ); + m_Client->Kick("Unsupported protocol version"); + return false; +} + + + + + +void cProtocolRecognizer::SendLengthlessServerPing(void) { AString Reply; switch (cRoot::Get()->GetPrimaryServerVersion()) @@ -757,10 +861,12 @@ void cProtocolRecognizer::HandleServerPing(void) // http://wiki.vg/wiki/index.php?title=Protocol&oldid=3101#Server_List_Ping_.280xFE.29 // _X 2012_10_31: I know that this needn't eat the byte, since it still may be in transit. // Who cares? We're disconnecting anyway. - if (m_Buffer.CanReadBytes(1)) + m_Buffer.ResetRead(); + if (m_Buffer.CanReadBytes(2)) { byte val; - m_Buffer.ReadByte(val); + m_Buffer.ReadByte(val); // Packet type - Serverlist ping + m_Buffer.ReadByte(val); // 0x01 magic value ASSERT(val == 0x01); } diff --git a/source/Protocol/ProtocolRecognizer.h b/source/Protocol/ProtocolRecognizer.h index c53288230..4c473a269 100644 --- a/source/Protocol/ProtocolRecognizer.h +++ b/source/Protocol/ProtocolRecognizer.h @@ -47,6 +47,9 @@ public: PROTO_VERSION_NEXT, PROTO_VERSION_LATEST = PROTO_VERSION_NEXT - 1, ///< Automatically assigned to the last protocol version, this serves as the default for PrimaryServerVersion + + // These will be kept "under" the next / latest, because the next and latest are only needed for previous protocols + PROTO_VERSION_1_7_2 = 4, } ; cProtocolRecognizer(cClientHandle * a_Client); @@ -124,8 +127,23 @@ protected: /// Tries to recognize protocol based on m_Buffer contents; returns true if recognized bool TryRecognizeProtocol(void); - /// Called when the recognizer gets a server ping packet; responds with server stats and destroys the client - void HandleServerPing(void); + /** Tries to recognize a protocol in the length-less family, based on m_Buffer; returns true if recognized. + Handles protocols before release 1.7, that didn't include packet lengths, and started with a 0x02 handshake packet + Note that length-less server ping is handled directly in TryRecognizeProtocol(), this function is called only + when the 0x02 Handshake packet has been received + */ + bool TryRecognizeLengthlessProtocol(void); + + /** Tries to recognize a protocol in the leghted family (1.7+), based on m_Buffer; returns true if recognized. + The packet length and type have already been read, type is 0 + The number of bytes remaining in the packet is passed as a_PacketLengthRemaining + **/ + bool TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining); + + /** Called when the recognizer gets a length-less protocol's server ping packet + Responds with server stats and destroys the client. + */ + void SendLengthlessServerPing(void); } ; |