diff --git a/example/com/github/steveice10/packetlib/test/PingServerTest.java b/example/com/github/steveice10/packetlib/test/PingServerTest.java index 7daa2b04..2db3b031 100644 --- a/example/com/github/steveice10/packetlib/test/PingServerTest.java +++ b/example/com/github/steveice10/packetlib/test/PingServerTest.java @@ -1,8 +1,9 @@ package com.github.steveice10.packetlib.test; -import com.github.steveice10.packetlib.Client; import com.github.steveice10.packetlib.Server; -import com.github.steveice10.packetlib.tcp.TcpSessionFactory; +import com.github.steveice10.packetlib.Session; +import com.github.steveice10.packetlib.tcp.TcpClientSession; +import com.github.steveice10.packetlib.tcp.TcpServer; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; @@ -10,7 +11,7 @@ import java.security.NoSuchAlgorithmException; public class PingServerTest { public static void main(String[] args) { - SecretKey key = null; + SecretKey key; try { KeyGenerator gen = KeyGenerator.getInstance("AES"); gen.init(128); @@ -20,19 +21,11 @@ public class PingServerTest { return; } - Server server = new Server("127.0.0.1", 25565, TestProtocol.class, new TcpSessionFactory()); + Server server = new TcpServer("127.0.0.1", 25565, TestProtocol.class); server.addListener(new ServerListener(key)); server.bind(); - Client client = new Client("127.0.0.1", 25565, new TestProtocol(key), new TcpSessionFactory()); - client.getSession().connect(); - - while(server.isListening()) { - try { - Thread.sleep(500); - } catch(InterruptedException e) { - break; - } - } + Session client = new TcpClientSession("127.0.0.1", 25565, new TestProtocol(key)); + client.connect(); } } diff --git a/example/com/github/steveice10/packetlib/test/ServerListener.java b/example/com/github/steveice10/packetlib/test/ServerListener.java index a0694ae1..3c7dfcb2 100644 --- a/example/com/github/steveice10/packetlib/test/ServerListener.java +++ b/example/com/github/steveice10/packetlib/test/ServerListener.java @@ -40,6 +40,6 @@ public class ServerListener extends ServerAdapter { @Override public void sessionRemoved(SessionRemovedEvent event) { System.out.println("SERVER Session Removed: " + event.getSession().getHost() + ":" + event.getSession().getPort()); - event.getServer().close(); + event.getServer().close(false); } } diff --git a/example/com/github/steveice10/packetlib/test/TestProtocol.java b/example/com/github/steveice10/packetlib/test/TestProtocol.java index e6ead1ae..8a4baedc 100644 --- a/example/com/github/steveice10/packetlib/test/TestProtocol.java +++ b/example/com/github/steveice10/packetlib/test/TestProtocol.java @@ -1,6 +1,5 @@ package com.github.steveice10.packetlib.test; -import com.github.steveice10.packetlib.Client; import com.github.steveice10.packetlib.Server; import com.github.steveice10.packetlib.Session; import com.github.steveice10.packetlib.crypt.AESEncryption; @@ -49,7 +48,7 @@ public class TestProtocol extends PacketProtocol { } @Override - public void newClientSession(Client client, Session session) { + public void newClientSession(Session session) { session.addListener(new ClientSessionListener()); } diff --git a/src/main/java/com/github/steveice10/packetlib/AbstractServer.java b/src/main/java/com/github/steveice10/packetlib/AbstractServer.java new file mode 100644 index 00000000..1412ccab --- /dev/null +++ b/src/main/java/com/github/steveice10/packetlib/AbstractServer.java @@ -0,0 +1,182 @@ +package com.github.steveice10.packetlib; + +import com.github.steveice10.packetlib.event.server.*; +import com.github.steveice10.packetlib.packet.PacketProtocol; + +import java.lang.reflect.Constructor; +import java.util.*; + +public abstract class AbstractServer implements Server { + private final String host; + private final int port; + private final Class protocol; + + private final List sessions = new ArrayList<>(); + + private final Map flags = new HashMap<>(); + private final List listeners = new ArrayList<>(); + + public AbstractServer(String host, int port, Class protocol) { + this.host = host; + this.port = port; + this.protocol = protocol; + } + + @Override + public String getHost() { + return this.host; + } + + @Override + public int getPort() { + return this.port; + } + + @Override + public Class getPacketProtocol() { + return this.protocol; + } + + protected PacketProtocol createPacketProtocol() { + try { + Constructor constructor = this.protocol.getDeclaredConstructor(); + if(!constructor.isAccessible()) { + constructor.setAccessible(true); + } + + return constructor.newInstance(); + } catch(NoSuchMethodError e) { + throw new IllegalStateException("PacketProtocol \"" + this.protocol.getName() + "\" does not have a no-params constructor for instantiation."); + } catch(Exception e) { + throw new IllegalStateException("Failed to instantiate PacketProtocol " + this.protocol.getName() + ".", e); + } + } + + @Override + public Map getGlobalFlags() { + return Collections.unmodifiableMap(this.flags); + } + + @Override + public boolean hasGlobalFlag(String key) { + return this.flags.containsKey(key); + } + + @Override + public T getGlobalFlag(String key) { + return this.getGlobalFlag(key, null); + } + + @SuppressWarnings("unchecked") + @Override + public T getGlobalFlag(String key, T def) { + Object value = this.flags.get(key); + if(value == null) { + return def; + } + + try { + return (T) value; + } catch(ClassCastException e) { + throw new IllegalStateException("Tried to get flag \"" + key + "\" as the wrong type. Actual type: " + value.getClass().getName()); + } + } + + @Override + public void setGlobalFlag(String key, Object value) { + this.flags.put(key, value); + } + + @Override + public List getListeners() { + return Collections.unmodifiableList(this.listeners); + } + + @Override + public void addListener(ServerListener listener) { + this.listeners.add(listener); + } + + @Override + public void removeListener(ServerListener listener) { + this.listeners.remove(listener); + } + + protected void callEvent(ServerEvent event) { + for(ServerListener listener : this.listeners) { + event.call(listener); + } + } + + @Override + public List getSessions() { + return new ArrayList<>(this.sessions); + } + + public void addSession(Session session) { + this.sessions.add(session); + this.callEvent(new SessionAddedEvent(this, session)); + } + + public void removeSession(Session session) { + this.sessions.remove(session); + if(session.isConnected()) { + session.disconnect("Connection closed."); + } + + this.callEvent(new SessionRemovedEvent(this, session)); + } + + @Override + public AbstractServer bind() { + return this.bind(true); + } + + @Override + public AbstractServer bind(boolean wait) { + return this.bind(wait, null); + } + + @Override + public AbstractServer bind(boolean wait, Runnable callback) { + this.bindImpl(wait, () -> { + callEvent(new ServerBoundEvent(AbstractServer.this)); + if(callback != null) { + callback.run(); + } + }); + + return this; + } + + protected abstract void bindImpl(boolean wait, Runnable callback); + + @Override + public void close() { + this.close(true); + } + + @Override + public void close(boolean wait) { + this.close(wait, null); + } + + @Override + public void close(boolean wait, Runnable callback) { + this.callEvent(new ServerClosingEvent(this)); + for(Session session : this.getSessions()) { + if(session.isConnected()) { + session.disconnect("Server closed."); + } + } + + this.closeImpl(wait, () -> { + callEvent(new ServerClosedEvent(AbstractServer.this)); + if(callback != null) { + callback.run(); + } + }); + } + + protected abstract void closeImpl(boolean wait, Runnable callback); +} diff --git a/src/main/java/com/github/steveice10/packetlib/Client.java b/src/main/java/com/github/steveice10/packetlib/Client.java deleted file mode 100644 index cf4237a1..00000000 --- a/src/main/java/com/github/steveice10/packetlib/Client.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.github.steveice10.packetlib; - -import com.github.steveice10.packetlib.packet.PacketProtocol; -import javax.annotation.Nullable; -import java.net.InetSocketAddress; - -/** - * A client that may connect to a server. - */ -public class Client { - private String host; - private int port; - private String bindAddress; - private int bindPort; - private PacketProtocol protocol; - private Session session; - - public Client(String host, int port, String bindAddress, int bindPort, PacketProtocol protocol, SessionFactory factory) { - this.host = host; - this.port = port; - this.bindAddress = bindAddress; - this.bindPort = bindPort; - this.protocol = protocol; - this.session = factory.createClientSession(this); - } - - public Client(String host, int port, PacketProtocol protocol, SessionFactory factory) { - this(host, port, "0.0.0.0", 0, protocol, factory); - } - - /** - * Gets the host the client is connecting to. - * - * @return The host the client is connecting to. - */ - public String getHost() { - return this.host; - } - - /** - * Gets the port the client is connecting to. - * - * @return The port the client is connecting to. - */ - public int getPort() { - return this.port; - } - - /** - * Gets the the local address the client is connected from/will be binding to. - * - * @return Client's local IP address, or null if default and not connected. - */ - @Nullable - public String getBindAddress() { - final Session session = this.getSession(); - return session.isConnected() - ? ((InetSocketAddress) session.getLocalAddress()).getAddress().getHostAddress() - : this.bindAddress; - } - - /** - * Gets the the local port the client is connected from/will be binding to. - * - * @return Client's local port, or 0 if default and not connected. - */ - public int getBindPort() { - final Session session = this.getSession(); - return session.isConnected() - ? ((InetSocketAddress) session.getLocalAddress()).getPort() - : this.bindPort; - } - - /** - * Gets the packet protocol of the client. - * - * @return The client's packet protocol. - */ - public PacketProtocol getPacketProtocol() { - return this.protocol; - } - - /** - * Gets the session of the client. - * - * @return The client's session. - */ - public Session getSession() { - return this.session; - } -} diff --git a/src/main/java/com/github/steveice10/packetlib/ConnectionListener.java b/src/main/java/com/github/steveice10/packetlib/ConnectionListener.java deleted file mode 100644 index 96cc5bd5..00000000 --- a/src/main/java/com/github/steveice10/packetlib/ConnectionListener.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.github.steveice10.packetlib; - -/** - * Listens for new sessions to connect. - */ -public interface ConnectionListener { - /** - * Gets the host the session is listening on. - * - * @return The listening host. - */ - public String getHost(); - - /** - * Gets the port the session is listening on. - * - * @return The listening port. - */ - public int getPort(); - - /** - * Returns true if the listener is listening. - * - * @return True if the listener is listening. - */ - public boolean isListening(); - - /** - * Binds the listener to its host and port. - */ - public void bind(); - - /** - * Binds the listener to its host and port. - * - * @param wait Whether to wait for the listener to finish binding. - */ - public void bind(boolean wait); - - /** - * Binds the listener to its host and port. - * - * @param wait Whether to wait for the listener to finish binding. - * @param callback Callback to call when the listener has finished binding. - */ - public void bind(boolean wait, Runnable callback); - - /** - * Closes the listener. - */ - public void close(); - - /** - * Closes the listener. - * - * @param wait Whether to wait for the listener to finish closing. - */ - public void close(boolean wait); - - /** - * Closes the listener. - * - * @param wait Whether to wait for the listener to finish closing. - * @param callback Callback to call when the listener has finished closing. - */ - public void close(boolean wait, Runnable callback); -} diff --git a/src/main/java/com/github/steveice10/packetlib/Server.java b/src/main/java/com/github/steveice10/packetlib/Server.java index 281fa977..2dd8fb60 100644 --- a/src/main/java/com/github/steveice10/packetlib/Server.java +++ b/src/main/java/com/github/steveice10/packetlib/Server.java @@ -1,125 +1,49 @@ package com.github.steveice10.packetlib; -import com.github.steveice10.packetlib.event.server.ServerBoundEvent; -import com.github.steveice10.packetlib.event.server.ServerClosedEvent; -import com.github.steveice10.packetlib.event.server.ServerClosingEvent; -import com.github.steveice10.packetlib.event.server.ServerEvent; import com.github.steveice10.packetlib.event.server.ServerListener; -import com.github.steveice10.packetlib.event.server.SessionAddedEvent; -import com.github.steveice10.packetlib.event.server.SessionRemovedEvent; import com.github.steveice10.packetlib.packet.PacketProtocol; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; /** - * A server that listens for connections. + * Listens for new sessions to connect. */ -public class Server { - private String host; - private int port; - private Class protocol; - private SessionFactory factory; - private ConnectionListener listener; - private List sessions = new ArrayList(); - - private Map flags = new HashMap(); - private List listeners = new ArrayList(); - - public Server(String host, int port, Class protocol, SessionFactory factory) { - this.host = host; - this.port = port; - this.protocol = protocol; - this.factory = factory; - } +public interface Server { + /** + * Gets the host the session is listening on. + * + * @return The listening host. + */ + public String getHost(); /** - * Binds and initializes the server. + * Gets the port the session is listening on. * - * @return The server after being bound. + * @return The listening port. */ - public Server bind() { - return this.bind(true); - } - - /** - * Binds and initializes the server. - * - * @param wait Whether to wait for the server to finish binding. - * @return The server after being bound. - */ - public Server bind(boolean wait) { - this.listener = this.factory.createServerListener(this); - this.listener.bind(wait, new Runnable() { - @Override - public void run() { - callEvent(new ServerBoundEvent(Server.this)); - } - }); - - return this; - } - - /** - * Gets the host this server is bound to. - * - * @return The server's host. - */ - public String getHost() { - return this.host; - } - - /** - * Gets the port this server is bound to. - * - * @return The server's port. - */ - public int getPort() { - return this.port; - } + public int getPort(); /** * Gets the packet protocol of the server. * * @return The server's packet protocol. */ - public Class getPacketProtocol() { - return this.protocol; - } + public Class getPacketProtocol(); /** - * Creates a new packet protocol instance from this server's protocol class. + * Returns true if the listener is listening. * - * @return The created protocol instance. - * @throws IllegalStateException If the protocol does not have a no-params constructor or cannot be instantiated. + * @return True if the listener is listening. */ - public PacketProtocol createPacketProtocol() { - try { - Constructor constructor = this.protocol.getDeclaredConstructor(); - if(!constructor.isAccessible()) { - constructor.setAccessible(true); - } - - return constructor.newInstance(); - } catch(NoSuchMethodError e) { - throw new IllegalStateException("PacketProtocol \"" + this.protocol.getName() + "\" does not have a no-params constructor for instantiation."); - } catch(Exception e) { - throw new IllegalStateException("Failed to instantiate PacketProtocol " + this.protocol.getName() + ".", e); - } - } + public boolean isListening(); /** * Gets this server's set flags. * * @return This server's flags. */ - public Map getGlobalFlags() { - return Collections.unmodifiableMap(this.flags); - } + public Map getGlobalFlags(); /** * Checks whether this server has a flag set. @@ -127,9 +51,7 @@ public class Server { * @param key Key of the flag to check for. * @return Whether this server has a flag set. */ - public boolean hasGlobalFlag(String key) { - return this.flags.containsKey(key); - } + public boolean hasGlobalFlag(String key); /** * Gets the value of the given flag as an instance of the given type. @@ -139,9 +61,7 @@ public class Server { * @return Value of the flag. * @throws IllegalStateException If the flag's value isn't of the required type. */ - public T getGlobalFlag(String key) { - return this.getGlobalFlag(key, null); - } + public T getGlobalFlag(String key); /** * Gets the value of the given flag as an instance of the given type. @@ -154,18 +74,7 @@ public class Server { * @throws IllegalStateException If the flag's value isn't of the required type. */ @SuppressWarnings("unchecked") - public T getGlobalFlag(String key, T def) { - Object value = this.flags.get(key); - if(value == null) { - return def; - } - - try { - return (T) value; - } catch(ClassCastException e) { - throw new IllegalStateException("Tried to get flag \"" + key + "\" as the wrong type. Actual type: " + value.getClass().getName()); - } - } + public T getGlobalFlag(String key, T def); /** * Sets the value of a flag. The flag will be used in sessions if a session does @@ -174,115 +83,73 @@ public class Server { * @param key Key of the flag. * @param value Value to set the flag to. */ - public void setGlobalFlag(String key, Object value) { - this.flags.put(key, value); - } + public void setGlobalFlag(String key, Object value); /** * Gets the listeners listening on this session. * * @return This server's listeners. */ - public List getListeners() { - return Collections.unmodifiableList(this.listeners); - } + public List getListeners(); /** * Adds a listener to this server. * * @param listener Listener to add. */ - public void addListener(ServerListener listener) { - this.listeners.add(listener); - } + public void addListener(ServerListener listener); /** * Removes a listener from this server. * * @param listener Listener to remove. */ - public void removeListener(ServerListener listener) { - this.listeners.remove(listener); - } - - /** - * Calls an event on the listeners of this server. - * - * @param event Event to call. - */ - public void callEvent(ServerEvent event) { - for(ServerListener listener : this.listeners) { - event.call(listener); - } - } + public void removeListener(ServerListener listener); /** * Gets all sessions belonging to this server. * * @return Sessions belonging to this server. */ - public List getSessions() { - return new ArrayList(this.sessions); - } + public List getSessions(); /** - * Adds the given session to this server. + * Binds the listener to its host and port. + */ + public AbstractServer bind(); + + /** + * Binds the listener to its host and port. * - * @param session Session to add. + * @param wait Whether to wait for the listener to finish binding. */ - public void addSession(Session session) { - this.sessions.add(session); - this.callEvent(new SessionAddedEvent(this, session)); - } + public AbstractServer bind(boolean wait); /** - * Removes the given session from this server. + * Binds the listener to its host and port. * - * @param session Session to remove. + * @param wait Whether to wait for the listener to finish binding. + * @param callback Callback to call when the listener has finished binding. */ - public void removeSession(Session session) { - this.sessions.remove(session); - if(session.isConnected()) { - session.disconnect("Connection closed."); - } - - this.callEvent(new SessionRemovedEvent(this, session)); - } + public AbstractServer bind(boolean wait, Runnable callback); /** - * Gets whether the server is listening. + * Closes the listener. + */ + public void close(); + + /** + * Closes the listener. * - * @return Whether the server is listening. + * @param wait Whether to wait for the listener to finish closing. */ - public boolean isListening() { - return this.listener != null && this.listener.isListening(); - } + public void close(boolean wait); /** - * Closes the server. - */ - public void close() { - this.close(true); - } - - /** - * Closes the server. + * Closes the listener. * - * @param wait Whether to wait for the server to finish closing. + * @param wait Whether to wait for the listener to finish closing. + * @param callback Callback to call when the listener has finished closing. */ - public void close(boolean wait) { - this.callEvent(new ServerClosingEvent(this)); - for(Session session : this.getSessions()) { - if(session.isConnected()) { - session.disconnect("Server closed."); - } - } - - this.listener.close(wait, new Runnable() { - @Override - public void run() { - callEvent(new ServerClosedEvent(Server.this)); - } - }); - } + public void close(boolean wait, Runnable callback); } diff --git a/src/main/java/com/github/steveice10/packetlib/SessionFactory.java b/src/main/java/com/github/steveice10/packetlib/SessionFactory.java deleted file mode 100644 index 5155af3c..00000000 --- a/src/main/java/com/github/steveice10/packetlib/SessionFactory.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.github.steveice10.packetlib; - -/** - * A factory for creating sessions. - */ -public interface SessionFactory { - /** - * Creates a client session. - * - * @param client Client to create the session for. - * @return The created session. - */ - public Session createClientSession(Client client); - - /** - * Creates a server network listener. - * - * @param server Server to create the listener for. - * @return The created listener. - */ - public ConnectionListener createServerListener(Server server); -} diff --git a/src/main/java/com/github/steveice10/packetlib/packet/PacketProtocol.java b/src/main/java/com/github/steveice10/packetlib/packet/PacketProtocol.java index 11556482..1cc93365 100644 --- a/src/main/java/com/github/steveice10/packetlib/packet/PacketProtocol.java +++ b/src/main/java/com/github/steveice10/packetlib/packet/PacketProtocol.java @@ -1,6 +1,5 @@ package com.github.steveice10.packetlib.packet; -import com.github.steveice10.packetlib.Client; import com.github.steveice10.packetlib.Server; import com.github.steveice10.packetlib.Session; import com.github.steveice10.packetlib.crypt.PacketEncryption; @@ -43,10 +42,9 @@ public abstract class PacketProtocol { /** * Called when a client session is created with this protocol. * - * @param client The client that the session belongs to. * @param session The created session. */ - public abstract void newClientSession(Client client, Session session); + public abstract void newClientSession(Session session); /** * Called when a server session is created with this protocol. diff --git a/src/main/java/com/github/steveice10/packetlib/tcp/TcpClientSession.java b/src/main/java/com/github/steveice10/packetlib/tcp/TcpClientSession.java index d6ef23a3..725e6068 100644 --- a/src/main/java/com/github/steveice10/packetlib/tcp/TcpClientSession.java +++ b/src/main/java/com/github/steveice10/packetlib/tcp/TcpClientSession.java @@ -1,7 +1,6 @@ package com.github.steveice10.packetlib.tcp; import com.github.steveice10.packetlib.BuiltinFlags; -import com.github.steveice10.packetlib.Client; import com.github.steveice10.packetlib.ProxyInfo; import com.github.steveice10.packetlib.packet.PacketProtocol; import io.netty.bootstrap.Bootstrap; @@ -41,14 +40,28 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; public class TcpClientSession extends TcpSession { - private Client client; + private String bindAddress; + private int bindPort; private ProxyInfo proxy; private EventLoopGroup group; - public TcpClientSession(String host, int port, PacketProtocol protocol, Client client, ProxyInfo proxy) { + public TcpClientSession(String host, int port, PacketProtocol protocol) { + this(host, port, protocol, null); + } + + public TcpClientSession(String host, int port, PacketProtocol protocol, ProxyInfo proxy) { + this(host, port, "0.0.0.0", 0, protocol, proxy); + } + + public TcpClientSession(String host, int port, String bindAddress, int bindPort, PacketProtocol protocol) { + this(host, port, bindAddress, bindPort, protocol, null); + } + + public TcpClientSession(String host, int port, String bindAddress, int bindPort, PacketProtocol protocol, ProxyInfo proxy) { super(host, port, protocol); - this.client = client; + this.bindAddress = bindAddress; + this.bindPort = bindPort; this.proxy = proxy; } @@ -67,8 +80,8 @@ public class TcpClientSession extends TcpSession { bootstrap.channel(NioSocketChannel.class); bootstrap.handler(new ChannelInitializer() { @Override - public void initChannel(Channel channel) throws Exception { - getPacketProtocol().newClientSession(client, TcpClientSession.this); + public void initChannel(Channel channel) { + getPacketProtocol().newClientSession(TcpClientSession.this); channel.config().setOption(ChannelOption.IP_TOS, 0x18); channel.config().setOption(ChannelOption.TCP_NODELAY, false); @@ -78,84 +91,34 @@ public class TcpClientSession extends TcpSession { refreshReadTimeoutHandler(channel); refreshWriteTimeoutHandler(channel); - if(proxy != null) { - switch(proxy.getType()) { - case HTTP: - if(proxy.isAuthenticated()) { - pipeline.addFirst("proxy", new HttpProxyHandler(proxy.getAddress(), proxy.getUsername(), proxy.getPassword())); - } else { - pipeline.addFirst("proxy", new HttpProxyHandler(proxy.getAddress())); - } - - break; - case SOCKS4: - if(proxy.isAuthenticated()) { - pipeline.addFirst("proxy", new Socks4ProxyHandler(proxy.getAddress(), proxy.getUsername())); - } else { - pipeline.addFirst("proxy", new Socks4ProxyHandler(proxy.getAddress())); - } - - break; - case SOCKS5: - if(proxy.isAuthenticated()) { - pipeline.addFirst("proxy", new Socks5ProxyHandler(proxy.getAddress(), proxy.getUsername(), proxy.getPassword())); - } else { - pipeline.addFirst("proxy", new Socks5ProxyHandler(proxy.getAddress())); - } - - break; - default: - throw new UnsupportedOperationException("Unsupported proxy type: " + proxy.getType()); - } - } + addProxy(pipeline); pipeline.addLast("encryption", new TcpPacketEncryptor(TcpClientSession.this)); pipeline.addLast("sizer", new TcpPacketSizer(TcpClientSession.this)); pipeline.addLast("codec", new TcpPacketCodec(TcpClientSession.this)); pipeline.addLast("manager", TcpClientSession.this); - InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS); - if (getFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, false) && clientAddress != null) { - pipeline.addFirst("proxy-protocol-packet-sender", new ChannelInboundHandlerAdapter() { - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6; - InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); - ctx.channel().writeAndFlush(new HAProxyMessage( - HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol, - clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(), - clientAddress.getPort(), remoteAddress.getPort() - )); - ctx.pipeline().remove(this); - ctx.pipeline().remove("proxy-protocol-encoder"); - super.channelActive(ctx); - } - }); - pipeline.addFirst("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE); - } + addHAProxySupport(pipeline); } }).group(this.group).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getConnectTimeout() * 1000); - Runnable connectTask = new Runnable() { - @Override - public void run() { - try { - InetSocketAddress remoteAddress = resolveAddress(); - bootstrap.remoteAddress(remoteAddress); - bootstrap.localAddress(client.getBindAddress(), client.getBindPort()); + Runnable connectTask = () -> { + try { + InetSocketAddress remoteAddress = resolveAddress(); + bootstrap.remoteAddress(remoteAddress); + bootstrap.localAddress(bindAddress, bindPort); - ChannelFuture future = bootstrap.connect().sync(); - if(future.isSuccess()) { - while(!isConnected() && !disconnected) { - try { - Thread.sleep(5); - } catch(InterruptedException e) { - } + ChannelFuture future = bootstrap.connect().sync(); + if(future.isSuccess()) { + while(!isConnected() && !disconnected) { + try { + Thread.sleep(5); + } catch(InterruptedException e) { } } - } catch(Throwable t) { - exceptionCaught(null, t); } + } catch(Throwable t) { + exceptionCaught(null, t); } }; @@ -241,6 +204,61 @@ public class TcpClientSession extends TcpSession { } } + private void addProxy(ChannelPipeline pipeline) { + if(proxy != null) { + switch(proxy.getType()) { + case HTTP: + if(proxy.isAuthenticated()) { + pipeline.addFirst("proxy", new HttpProxyHandler(proxy.getAddress(), proxy.getUsername(), proxy.getPassword())); + } else { + pipeline.addFirst("proxy", new HttpProxyHandler(proxy.getAddress())); + } + + break; + case SOCKS4: + if(proxy.isAuthenticated()) { + pipeline.addFirst("proxy", new Socks4ProxyHandler(proxy.getAddress(), proxy.getUsername())); + } else { + pipeline.addFirst("proxy", new Socks4ProxyHandler(proxy.getAddress())); + } + + break; + case SOCKS5: + if(proxy.isAuthenticated()) { + pipeline.addFirst("proxy", new Socks5ProxyHandler(proxy.getAddress(), proxy.getUsername(), proxy.getPassword())); + } else { + pipeline.addFirst("proxy", new Socks5ProxyHandler(proxy.getAddress())); + } + + break; + default: + throw new UnsupportedOperationException("Unsupported proxy type: " + proxy.getType()); + } + } + } + + private void addHAProxySupport(ChannelPipeline pipeline) { + InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS); + if (getFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, false) && clientAddress != null) { + pipeline.addFirst("proxy-protocol-packet-sender", new ChannelInboundHandlerAdapter() { + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6; + InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); + ctx.channel().writeAndFlush(new HAProxyMessage( + HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol, + clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(), + clientAddress.getPort(), remoteAddress.getPort() + )); + ctx.pipeline().remove(this); + ctx.pipeline().remove("proxy-protocol-encoder"); + super.channelActive(ctx); + } + }); + pipeline.addFirst("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE); + } + } + @Override public void disconnect(String reason, Throwable cause) { super.disconnect(reason, cause); diff --git a/src/main/java/com/github/steveice10/packetlib/tcp/TcpConnectionListener.java b/src/main/java/com/github/steveice10/packetlib/tcp/TcpServer.java similarity index 69% rename from src/main/java/com/github/steveice10/packetlib/tcp/TcpConnectionListener.java rename to src/main/java/com/github/steveice10/packetlib/tcp/TcpServer.java index 35650af8..3a1ab09d 100644 --- a/src/main/java/com/github/steveice10/packetlib/tcp/TcpConnectionListener.java +++ b/src/main/java/com/github/steveice10/packetlib/tcp/TcpServer.java @@ -1,6 +1,7 @@ package com.github.steveice10.packetlib.tcp; -import com.github.steveice10.packetlib.ConnectionListener; +import com.github.steveice10.packetlib.AbstractServer; +import com.github.steveice10.packetlib.BuiltinFlags; import com.github.steveice10.packetlib.Server; import com.github.steveice10.packetlib.packet.PacketProtocol; import io.netty.bootstrap.ServerBootstrap; @@ -18,28 +19,12 @@ import io.netty.util.concurrent.GenericFutureListener; import java.net.InetSocketAddress; -public class TcpConnectionListener implements ConnectionListener { - private String host; - private int port; - private Server server; - +public class TcpServer extends AbstractServer { private EventLoopGroup group; private Channel channel; - public TcpConnectionListener(String host, int port, Server server) { - this.host = host; - this.port = port; - this.server = server; - } - - @Override - public String getHost() { - return this.host; - } - - @Override - public int getPort() { - return this.port; + public TcpServer(String host, int port, Class protocol) { + super(host, port, protocol); } @Override @@ -48,17 +33,7 @@ public class TcpConnectionListener implements ConnectionListener { } @Override - public void bind() { - this.bind(true); - } - - @Override - public void bind(boolean wait) { - this.bind(wait, null); - } - - @Override - public void bind(boolean wait, final Runnable callback) { + public void bindImpl(boolean wait, final Runnable callback) { if(this.group != null || this.channel != null) { return; } @@ -68,10 +43,10 @@ public class TcpConnectionListener implements ConnectionListener { @Override public void initChannel(Channel channel) throws Exception { InetSocketAddress address = (InetSocketAddress) channel.remoteAddress(); - PacketProtocol protocol = server.createPacketProtocol(); + PacketProtocol protocol = createPacketProtocol(); - TcpSession session = new TcpServerSession(address.getHostName(), address.getPort(), protocol, server); - session.getPacketProtocol().newServerSession(server, session); + TcpSession session = new TcpServerSession(address.getHostName(), address.getPort(), protocol, TcpServer.this); + session.getPacketProtocol().newServerSession(TcpServer.this, session); channel.config().setOption(ChannelOption.IP_TOS, 0x18); channel.config().setOption(ChannelOption.TCP_NODELAY, false); @@ -86,7 +61,7 @@ public class TcpConnectionListener implements ConnectionListener { pipeline.addLast("codec", new TcpPacketCodec(session)); pipeline.addLast("manager", session); } - }).group(this.group).localAddress(this.host, this.port).bind(); + }).group(this.group).localAddress(this.getHost(), this.getPort()).bind(); if(wait) { try { @@ -119,17 +94,7 @@ public class TcpConnectionListener implements ConnectionListener { } @Override - public void close() { - this.close(false); - } - - @Override - public void close(boolean wait) { - this.close(wait, null); - } - - @Override - public void close(boolean wait, final Runnable callback) { + public void closeImpl(boolean wait, final Runnable callback) { if(this.channel != null) { if(this.channel.isOpen()) { ChannelFuture future = this.channel.close(); @@ -143,18 +108,15 @@ public class TcpConnectionListener implements ConnectionListener { callback.run(); } } else { - future.addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if(future.isSuccess()) { - if(callback != null) { - callback.run(); - } - } else { - System.err.println("[ERROR] Failed to asynchronously close connection listener."); - if(future.cause() != null) { - future.cause().printStackTrace(); - } + future.addListener((ChannelFutureListener) future1 -> { + if(future1.isSuccess()) { + if(callback != null) { + callback.run(); + } + } else { + System.err.println("[ERROR] Failed to asynchronously close connection listener."); + if(future1.cause() != null) { + future1.cause().printStackTrace(); } } }); @@ -174,8 +136,8 @@ public class TcpConnectionListener implements ConnectionListener { } else { future.addListener(new GenericFutureListener() { @Override - public void operationComplete(Future future) throws Exception { - if(!future.isSuccess()) { + public void operationComplete(Future future) { + if(!future.isSuccess() && getGlobalFlag(BuiltinFlags.PRINT_DEBUG, false)) { System.err.println("[ERROR] Failed to asynchronously close connection listener."); if(future.cause() != null) { future.cause().printStackTrace(); diff --git a/src/main/java/com/github/steveice10/packetlib/tcp/TcpServerSession.java b/src/main/java/com/github/steveice10/packetlib/tcp/TcpServerSession.java index 4d0f205a..8591fb92 100644 --- a/src/main/java/com/github/steveice10/packetlib/tcp/TcpServerSession.java +++ b/src/main/java/com/github/steveice10/packetlib/tcp/TcpServerSession.java @@ -8,9 +8,9 @@ import java.util.HashMap; import java.util.Map; public class TcpServerSession extends TcpSession { - private Server server; + private TcpServer server; - public TcpServerSession(String host, int port, PacketProtocol protocol, Server server) { + public TcpServerSession(String host, int port, PacketProtocol protocol, TcpServer server) { super(host, port, protocol); this.server = server; } diff --git a/src/main/java/com/github/steveice10/packetlib/tcp/TcpSession.java b/src/main/java/com/github/steveice10/packetlib/tcp/TcpSession.java index e5f1347b..2ce8b375 100644 --- a/src/main/java/com/github/steveice10/packetlib/tcp/TcpSession.java +++ b/src/main/java/com/github/steveice10/packetlib/tcp/TcpSession.java @@ -253,12 +253,9 @@ public abstract class TcpSession extends SimpleChannelInboundHandler imp if(this.channel != null && this.channel.isOpen()) { this.callEvent(new DisconnectingEvent(this, reason, cause)); - this.channel.flush().close().addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - callEvent(new DisconnectedEvent(TcpSession.this, reason != null ? reason : "Connection closed.", cause)); - } - }); + this.channel.flush().close().addListener((ChannelFutureListener) future -> + callEvent(new DisconnectedEvent(TcpSession.this, + reason != null ? reason : "Connection closed.", cause))); } else { this.callEvent(new DisconnectedEvent(this, reason != null ? reason : "Connection closed.", cause)); } diff --git a/src/main/java/com/github/steveice10/packetlib/tcp/TcpSessionFactory.java b/src/main/java/com/github/steveice10/packetlib/tcp/TcpSessionFactory.java deleted file mode 100644 index 0fad540e..00000000 --- a/src/main/java/com/github/steveice10/packetlib/tcp/TcpSessionFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.github.steveice10.packetlib.tcp; - -import com.github.steveice10.packetlib.Client; -import com.github.steveice10.packetlib.ConnectionListener; -import com.github.steveice10.packetlib.ProxyInfo; -import com.github.steveice10.packetlib.Server; -import com.github.steveice10.packetlib.Session; -import com.github.steveice10.packetlib.SessionFactory; - -/** - * A session factory used to create TCP sessions. - */ -public class TcpSessionFactory implements SessionFactory { - private ProxyInfo clientProxy; - - public TcpSessionFactory() { - } - - public TcpSessionFactory(ProxyInfo clientProxy) { - this.clientProxy = clientProxy; - } - - @Override - public Session createClientSession(final Client client) { - return new TcpClientSession(client.getHost(), client.getPort(), client.getPacketProtocol(), client, this.clientProxy); - } - - @Override - public ConnectionListener createServerListener(final Server server) { - return new TcpConnectionListener(server.getHost(), server.getPort(), server); - } -}