Use custom packet out stream to ease transition to a netty channel when it is required

This commit is contained in:
md_5 2013-02-09 17:48:42 +11:00
parent fbede036d8
commit 69d618c648
6 changed files with 63 additions and 50 deletions

View File

@ -14,7 +14,7 @@ import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.packet.DefinedPacket; import net.md_5.bungee.packet.DefinedPacket;
import net.md_5.bungee.packet.PacketFAPluginMessage; import net.md_5.bungee.packet.PacketFAPluginMessage;
import net.md_5.bungee.packet.PacketFFKick; import net.md_5.bungee.packet.PacketFFKick;
import net.md_5.bungee.packet.PacketInputStream; import net.md_5.bungee.packet.PacketStream;
public class BungeeServerInfo extends ServerInfo public class BungeeServerInfo extends ServerInfo
{ {
@ -57,7 +57,7 @@ public class BungeeServerInfo extends ServerInfo
out.write(0xFE); out.write(0xFE);
out.write(0x01); out.write(0x01);
} }
try (PacketInputStream in = new PacketInputStream(socket.getInputStream())) try (PacketStream in = new PacketStream(socket.getInputStream()))
{ {
PacketFFKick response = new PacketFFKick(in.readPacket()); PacketFFKick response = new PacketFFKick(in.readPacket());

View File

@ -8,7 +8,7 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import static net.md_5.bungee.Logger.$; import static net.md_5.bungee.Logger.$;
import net.md_5.bungee.packet.PacketFFKick; import net.md_5.bungee.packet.PacketFFKick;
import net.md_5.bungee.packet.PacketInputStream; import net.md_5.bungee.packet.PacketStream;
/** /**
* Class to represent a Minecraft connection. * Class to represent a Minecraft connection.
@ -19,8 +19,7 @@ public class GenericConnection
{ {
protected final Socket socket; protected final Socket socket;
protected final PacketInputStream in; protected final PacketStream stream;
protected final OutputStream out;
@Getter @Getter
public String name; public String name;
@Getter @Getter
@ -40,15 +39,14 @@ public class GenericConnection
log("disconnected with " + reason); log("disconnected with " + reason);
try try
{ {
out.write(new PacketFFKick("[Proxy] " + reason).getPacket()); stream.write(new PacketFFKick("[Proxy] " + reason));
} catch (IOException ex) } catch (IOException ex)
{ {
} finally } finally
{ {
try try
{ {
out.flush(); socket.shutdownOutput();
out.close();
socket.close(); socket.close();
} catch (IOException ioe) } catch (IOException ioe)
{ {

View File

@ -24,7 +24,7 @@ import net.md_5.bungee.packet.PacketFDEncryptionRequest;
import net.md_5.bungee.packet.PacketFEPing; import net.md_5.bungee.packet.PacketFEPing;
import net.md_5.bungee.packet.PacketFFKick; import net.md_5.bungee.packet.PacketFFKick;
import net.md_5.bungee.packet.PacketHandler; import net.md_5.bungee.packet.PacketHandler;
import net.md_5.bungee.packet.PacketInputStream; import net.md_5.bungee.packet.PacketStream;
import org.bouncycastle.crypto.io.CipherInputStream; import org.bouncycastle.crypto.io.CipherInputStream;
import org.bouncycastle.crypto.io.CipherOutputStream; import org.bouncycastle.crypto.io.CipherOutputStream;
@ -34,8 +34,7 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo
private final Socket socket; private final Socket socket;
@Getter @Getter
private final ListenerInfo listener; private final ListenerInfo listener;
private PacketInputStream in; private PacketStream stream;
private OutputStream out;
private Packet2Handshake handshake; private Packet2Handshake handshake;
private PacketFDEncryptionRequest request; private PacketFDEncryptionRequest request;
private State thisState = State.HANDSHAKE; private State thisState = State.HANDSHAKE;
@ -44,8 +43,7 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo
{ {
this.socket = socket; this.socket = socket;
this.listener = info; this.listener = info;
in = new PacketInputStream(socket.getInputStream()); stream = new PacketStream(socket.getInputStream(), socket.getOutputStream());
out = socket.getOutputStream();
} }
private enum State private enum State
@ -88,7 +86,7 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo
Preconditions.checkState(thisState == State.HANDSHAKE, "Not expecting HANDSHAKE"); Preconditions.checkState(thisState == State.HANDSHAKE, "Not expecting HANDSHAKE");
this.handshake = handshake; this.handshake = handshake;
request = EncryptionUtil.encryptRequest(); request = EncryptionUtil.encryptRequest();
out.write(request.getPacket()); stream.write(request);
thisState = State.ENCRYPT; thisState = State.ENCRYPT;
} }
@ -117,9 +115,9 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo
disconnect(event.getCancelReason()); disconnect(event.getCancelReason());
} }
out.write(new PacketFCEncryptionResponse().getPacket()); stream.write(new PacketFCEncryptionResponse());
in = new PacketInputStream(new CipherInputStream(socket.getInputStream(), EncryptionUtil.getCipher(false, shared))); stream = new PacketStream(new CipherInputStream(socket.getInputStream(),
out = new CipherOutputStream(socket.getOutputStream(), EncryptionUtil.getCipher(true, shared)); EncryptionUtil.getCipher(false, shared)), new CipherOutputStream(socket.getOutputStream(), EncryptionUtil.getCipher(true, shared)));
thisState = State.LOGIN; thisState = State.LOGIN;
} }
@ -129,7 +127,7 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo
{ {
Preconditions.checkState(thisState == State.LOGIN, "Not expecting LOGIN"); Preconditions.checkState(thisState == State.LOGIN, "Not expecting LOGIN");
UserConnection userCon = new UserConnection(socket, this, in, out, handshake); UserConnection userCon = new UserConnection(socket, this, stream, handshake);
String server = ProxyServer.getInstance().getReconnectHandler().getServer(userCon); String server = ProxyServer.getInstance().getReconnectHandler().getServer(userCon);
ServerInfo s = BungeeCord.getInstance().config.getServers().get(server); ServerInfo s = BungeeCord.getInstance().config.getServers().get(server);
userCon.connect(s, true); userCon.connect(s, true);
@ -144,7 +142,7 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo
{ {
while (thisState != State.FINISHED) while (thisState != State.FINISHED)
{ {
byte[] buf = in.readPacket(); byte[] buf = stream.readPacket();
DefinedPacket packet = DefinedPacket.packet(buf); DefinedPacket packet = DefinedPacket.packet(buf);
packet.handle(this); packet.handle(this);
} }
@ -161,7 +159,7 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo
thisState = State.FINISHED; thisState = State.FINISHED;
try try
{ {
out.write(new PacketFFKick(reason).getPacket()); stream.write(new PacketFFKick(reason));
} catch (IOException ioe) } catch (IOException ioe)
{ {
} finally } finally

View File

@ -1,6 +1,5 @@
package net.md_5.bungee; package net.md_5.bungee;
import java.io.OutputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.util.Queue; import java.util.Queue;
@ -18,9 +17,8 @@ import net.md_5.bungee.packet.Packet1Login;
import net.md_5.bungee.packet.Packet2Handshake; import net.md_5.bungee.packet.Packet2Handshake;
import net.md_5.bungee.packet.PacketCDClientStatus; import net.md_5.bungee.packet.PacketCDClientStatus;
import net.md_5.bungee.packet.PacketFAPluginMessage; import net.md_5.bungee.packet.PacketFAPluginMessage;
import net.md_5.bungee.packet.PacketFDEncryptionRequest;
import net.md_5.bungee.packet.PacketFFKick; import net.md_5.bungee.packet.PacketFFKick;
import net.md_5.bungee.packet.PacketInputStream; import net.md_5.bungee.packet.PacketStream;
/** /**
* Class representing a connection from the proxy to the server; ie upstream. * Class representing a connection from the proxy to the server; ie upstream.
@ -33,9 +31,9 @@ public class ServerConnection extends GenericConnection implements Server
public final Packet1Login loginPacket; public final Packet1Login loginPacket;
public Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>(); public Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
public ServerConnection(Socket socket, ServerInfo info, PacketInputStream in, OutputStream out, Packet1Login loginPacket) public ServerConnection(Socket socket, ServerInfo info, PacketStream stream, Packet1Login loginPacket)
{ {
super(socket, in, out); super(socket, stream);
this.info = info; this.info = info;
this.loginPacket = loginPacket; this.loginPacket = loginPacket;
} }
@ -48,30 +46,29 @@ public class ServerConnection extends GenericConnection implements Server
socket.connect(info.getAddress(), BungeeCord.getInstance().config.getTimeout()); socket.connect(info.getAddress(), BungeeCord.getInstance().config.getTimeout());
BungeeCord.getInstance().setSocketOptions(socket); BungeeCord.getInstance().setSocketOptions(socket);
PacketInputStream in = new PacketInputStream(socket.getInputStream()); PacketStream stream = new PacketStream(socket.getInputStream(), socket.getOutputStream());
OutputStream out = socket.getOutputStream();
out.write(handshake.getPacket()); stream.write(handshake);
out.write(new PacketCDClientStatus((byte) 0).getPacket()); stream.write(new PacketCDClientStatus((byte) 0));
in.readPacket(); stream.readPacket();
byte[] loginResponse = in.readPacket(); byte[] loginResponse = stream.readPacket();
if (Util.getId(loginResponse) == 0xFF) if (Util.getId(loginResponse) == 0xFF)
{ {
throw new KickException("[Kicked] " + new PacketFFKick(loginResponse).message); throw new KickException("[Kicked] " + new PacketFFKick(loginResponse).message);
} }
Packet1Login login = new Packet1Login(loginResponse); Packet1Login login = new Packet1Login(loginResponse);
ServerConnection server = new ServerConnection(socket, info, in, out, login); ServerConnection server = new ServerConnection(socket, info, stream, login);
ServerConnectedEvent event = new ServerConnectedEvent(user, server); ServerConnectedEvent event = new ServerConnectedEvent(user, server);
ProxyServer.getInstance().getPluginManager().callEvent(event); ProxyServer.getInstance().getPluginManager().callEvent(event);
out.write(BungeeCord.getInstance().registerChannels().getPacket()); stream.write(BungeeCord.getInstance().registerChannels());
Queue<DefinedPacket> packetQueue = ((BungeeServerInfo) info).getPacketQueue(); Queue<DefinedPacket> packetQueue = ((BungeeServerInfo) info).getPacketQueue();
while (!packetQueue.isEmpty()) while (!packetQueue.isEmpty())
{ {
out.write(packetQueue.poll().getPacket()); stream.write(packetQueue.poll());
} }
return server; return server;

View File

@ -54,9 +54,9 @@ public class UserConnection extends GenericConnection implements ProxiedPlayer
// Hack for connect timings // Hack for connect timings
private ServerInfo nextServer; private ServerInfo nextServer;
public UserConnection(Socket socket, PendingConnection pendingConnection, PacketInputStream in, OutputStream out, Packet2Handshake handshake) public UserConnection(Socket socket, PendingConnection pendingConnection, PacketStream stream, Packet2Handshake handshake)
{ {
super(socket, in, out); super(socket, stream);
this.handshake = handshake; this.handshake = handshake;
this.pendingConnection = pendingConnection; this.pendingConnection = pendingConnection;
name = handshake.username; name = handshake.username;
@ -103,8 +103,8 @@ public class UserConnection extends GenericConnection implements ProxiedPlayer
if (server != null) if (server != null)
{ {
out.write(new Packet9Respawn((byte) 1, (byte) 0, (byte) 0, (short) 256, "DEFAULT").getPacket()); stream.write(new Packet9Respawn((byte) 1, (byte) 0, (byte) 0, (short) 256, "DEFAULT"));
out.write(new Packet9Respawn((byte) -1, (byte) 0, (byte) 0, (short) 256, "DEFAULT").getPacket()); stream.write(new Packet9Respawn((byte) -1, (byte) 0, (byte) 0, (short) 256, "DEFAULT"));
} }
ServerConnection newServer = ServerConnection.connect(this, target, handshake, true); ServerConnection newServer = ServerConnection.connect(this, target, handshake, true);
@ -113,8 +113,8 @@ public class UserConnection extends GenericConnection implements ProxiedPlayer
// Once again, first connection // Once again, first connection
clientEntityId = newServer.loginPacket.entityId; clientEntityId = newServer.loginPacket.entityId;
serverEntityId = newServer.loginPacket.entityId; serverEntityId = newServer.loginPacket.entityId;
out.write(newServer.loginPacket.getPacket()); stream.write(newServer.loginPacket);
out.write(BungeeCord.getInstance().registerChannels().getPacket()); stream.write(BungeeCord.getInstance().registerChannels());
upBridge = new UpstreamBridge(); upBridge = new UpstreamBridge();
upBridge.start(); upBridge.start();
@ -133,7 +133,7 @@ public class UserConnection extends GenericConnection implements ProxiedPlayer
Packet1Login login = newServer.loginPacket; Packet1Login login = newServer.loginPacket;
serverEntityId = login.entityId; serverEntityId = login.entityId;
out.write(new Packet9Respawn(login.dimension, login.difficulty, login.gameMode, (short) 256, login.levelType).getPacket()); stream.write(new Packet9Respawn(login.dimension, login.difficulty, login.gameMode, (short) 256, login.levelType));
} }
// Reconnect process has finished, lets get the player moving again // Reconnect process has finished, lets get the player moving again
@ -259,7 +259,7 @@ public class UserConnection extends GenericConnection implements ProxiedPlayer
{ {
try try
{ {
byte[] packet = in.readPacket(); byte[] packet = stream.readPacket();
boolean sendPacket = true; boolean sendPacket = true;
int id = Util.getId(packet); int id = Util.getId(packet);
@ -310,14 +310,14 @@ public class UserConnection extends GenericConnection implements ProxiedPlayer
DefinedPacket p = server.packetQueue.poll(); DefinedPacket p = server.packetQueue.poll();
if (p != null) if (p != null)
{ {
server.out.write(p.getPacket()); server.stream.write(p);
} }
} }
EntityMap.rewrite(packet, clientEntityId, serverEntityId); EntityMap.rewrite(packet, clientEntityId, serverEntityId);
if (sendPacket && !server.socket.isClosed()) if (sendPacket && !server.socket.isClosed())
{ {
server.out.write(packet); server.stream.write(packet);
} }
} catch (IOException ex) } catch (IOException ex)
{ {
@ -346,7 +346,7 @@ public class UserConnection extends GenericConnection implements ProxiedPlayer
outer: outer:
while (!reconnecting) while (!reconnecting)
{ {
byte[] packet = server.in.readPacket(); byte[] packet = server.stream.readPacket();
int id = Util.getId(packet); int id = Util.getId(packet);
switch (id) switch (id)
@ -502,12 +502,12 @@ public class UserConnection extends GenericConnection implements ProxiedPlayer
DefinedPacket p = packetQueue.poll(); DefinedPacket p = packetQueue.poll();
if (p != null) if (p != null)
{ {
out.write(p.getPacket()); stream.write(p);
} }
} }
EntityMap.rewrite(packet, serverEntityId, clientEntityId); EntityMap.rewrite(packet, serverEntityId, clientEntityId);
out.write(packet); stream.write(packet);
if (nextServer != null) if (nextServer != null)
{ {

View File

@ -5,24 +5,44 @@ import java.io.DataInputStream;
import java.io.FilterInputStream; import java.io.FilterInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import lombok.Getter;
import lombok.Setter;
import net.md_5.mendax.datainput.DataInputPacketReader; import net.md_5.mendax.datainput.DataInputPacketReader;
import org.bouncycastle.crypto.io.CipherInputStream;
/** /**
* A specialized input stream to parse packets using the Mojang packet * A specialized input stream to parse packets using the Mojang packet
* definitions and then return them as a byte array. * definitions and then return them as a byte array.
*/ */
public class PacketInputStream implements AutoCloseable public class PacketStream implements AutoCloseable
{ {
private final DataInputStream dataInput; private final DataInputStream dataInput;
@Getter
private OutputStream out;
private final TrackingInputStream tracker; private final TrackingInputStream tracker;
private final byte[] buffer = new byte[1 << 18]; private final byte[] buffer = new byte[1 << 18];
public PacketInputStream(InputStream in) public PacketStream(InputStream in)
{
this(in, null);
}
public PacketStream(InputStream in, OutputStream out)
{ {
tracker = new TrackingInputStream(in); tracker = new TrackingInputStream(in);
dataInput = new DataInputStream(tracker); dataInput = new DataInputStream(tracker);
this.out = out;
}
public void write(byte[] b) throws IOException
{
out.write(b);
}
public void write(DefinedPacket packet) throws IOException
{
out.write(packet.getPacket());
} }
/** /**