Collapse Client and Server into *ClientSession and ConnectionListener.

This commit is contained in:
Steveice10 2021-01-15 12:42:00 -08:00
parent 87206da886
commit 19a9b2be35
14 changed files with 356 additions and 552 deletions

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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());
}

View file

@ -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<? extends PacketProtocol> protocol;
private final List<Session> sessions = new ArrayList<>();
private final Map<String, Object> flags = new HashMap<>();
private final List<ServerListener> listeners = new ArrayList<>();
public AbstractServer(String host, int port, Class<? extends PacketProtocol> 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<? extends PacketProtocol> getPacketProtocol() {
return this.protocol;
}
protected PacketProtocol createPacketProtocol() {
try {
Constructor<? extends PacketProtocol> 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<String, Object> getGlobalFlags() {
return Collections.unmodifiableMap(this.flags);
}
@Override
public boolean hasGlobalFlag(String key) {
return this.flags.containsKey(key);
}
@Override
public <T> T getGlobalFlag(String key) {
return this.getGlobalFlag(key, null);
}
@SuppressWarnings("unchecked")
@Override
public <T> 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<ServerListener> 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<Session> 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);
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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<? extends PacketProtocol> protocol;
private SessionFactory factory;
private ConnectionListener listener;
private List<Session> sessions = new ArrayList<Session>();
private Map<String, Object> flags = new HashMap<String, Object>();
private List<ServerListener> listeners = new ArrayList<ServerListener>();
public Server(String host, int port, Class<? extends PacketProtocol> 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<? extends PacketProtocol> getPacketProtocol() {
return this.protocol;
}
public Class<? extends PacketProtocol> 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<? extends PacketProtocol> 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<String, Object> getGlobalFlags() {
return Collections.unmodifiableMap(this.flags);
}
public Map<String, Object> 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> T getGlobalFlag(String key) {
return this.getGlobalFlag(key, null);
}
public <T> 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> 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> 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<ServerListener> getListeners() {
return Collections.unmodifiableList(this.listeners);
}
public List<ServerListener> 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<Session> getSessions() {
return new ArrayList<Session>(this.sessions);
}
public List<Session> 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);
}

View file

@ -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);
}

View file

@ -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.

View file

@ -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<Channel>() {
@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);

View file

@ -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<? extends PacketProtocol> 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();

View file

@ -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;
}

View file

@ -253,12 +253,9 @@ public abstract class TcpSession extends SimpleChannelInboundHandler<Packet> 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));
}

View file

@ -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);
}
}