001/* 002 * Trident - A Multithreaded Server Alternative 003 * Copyright 2014 The TridentSDK Team 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package net.tridentsdk.server.netty.packet; 019 020import io.netty.channel.ChannelHandlerContext; 021import io.netty.channel.SimpleChannelInboundHandler; 022import net.tridentsdk.Trident; 023import net.tridentsdk.meta.MessageBuilder; 024import net.tridentsdk.server.TridentServer; 025import net.tridentsdk.server.netty.ClientConnection; 026import net.tridentsdk.server.netty.protocol.Protocol; 027import net.tridentsdk.server.packets.login.PacketLoginOutDisconnect; 028import net.tridentsdk.server.packets.play.in.PacketPlayInPlayerFall; 029import net.tridentsdk.server.packets.play.in.PacketPlayInPlayerMove; 030import net.tridentsdk.server.packets.play.out.PacketPlayOutDisconnect; 031import net.tridentsdk.server.player.PlayerConnection; 032import net.tridentsdk.util.TridentLogger; 033 034import javax.annotation.concurrent.ThreadSafe; 035 036/** 037 * The channel handler that is placed into the netty connection bootstrap to process inbound messages from clients (not 038 * just onlinePlayers) 039 * 040 * @author The TridentSDK Team 041 */ 042@ThreadSafe 043public class PacketHandler extends SimpleChannelInboundHandler<PacketData> { 044 private final Protocol protocol; 045 private ClientConnection connection; 046 047 public PacketHandler() { 048 this.protocol = ((TridentServer) Trident.instance()).protocol(); 049 } 050 051 @Override 052 public void handlerAdded(ChannelHandlerContext context) { 053 this.connection = ClientConnection.connection(context); 054 } 055 056 /** 057 * Converts the PacketData to a Packet depending on the ConnectionStage of the Client {@inheritDoc} 058 */ 059 @Override 060 protected void messageReceived(ChannelHandlerContext context, PacketData data) throws Exception { 061 Packet packet = this.protocol.getPacket(data.id(), this.connection.stage(), PacketDirection.IN); 062 063 //If packet is unknown disconnect the client, as said client seems to be modified 064 if (packet.id() == -1) { 065 this.connection.logout(); 066 067 if(connection instanceof PlayerConnection) { 068 PlayerConnection con = (PlayerConnection) connection; 069 070 TridentLogger.get().log(con.player().displayName() + " has been disconnected from the server " + 071 "for sending an invalid packet (" + 072 con.address().getHostString() + "," + con.player().uniqueId().toString() + 073 "," + data.id() + ")"); 074 } 075 return; 076 } 077 078 // decode and handle the packet 079 packet.decode(data.data()); 080 081 try { 082 // DEBUG ===== 083 if (!(packet instanceof PacketPlayInPlayerFall) && !(packet instanceof PacketPlayInPlayerMove)) 084 TridentLogger.get().debug("Received packet " + packet.getClass().getSimpleName()); 085 // ===== 086 087 //TODO: add plugin registration for packet handling 088 089 packet.handleReceived(this.connection); 090 091 if (connection instanceof PlayerConnection) { 092 ((PlayerConnection) connection).resetReadCounter(); 093 } 094 } catch (Exception ex) { 095 TridentLogger.get().error(ex); 096 097 switch (this.connection.stage()) { 098 case LOGIN: 099 PacketLoginOutDisconnect disconnect = new PacketLoginOutDisconnect(); 100 101 disconnect.setJsonMessage(ex.getMessage()); 102 103 this.connection.sendPacket(disconnect); 104 this.connection.logout(); 105 106 // fall through 107 108 case PLAY: 109 PacketPlayOutDisconnect quit = new PacketPlayOutDisconnect(); 110 111 quit.set("reason", new MessageBuilder("\"Internal Error: " + ex.getClass().getName() + 112 ((ex.getMessage() != null) ? ": " + ex.getMessage() : "") + "\"").build().asJson()); 113 114 this.connection.sendPacket(quit); 115 this.connection.logout(); 116 117 // fall through 118 119 default: 120 break; 121 } 122 } 123 } 124 125 public void updateConnection(PlayerConnection connection) { 126 this.connection = connection; 127 } 128}