mirror of
https://github.com/GeyserMC/MCProtocolLib.git
synced 2024-12-04 12:51:09 -05:00
Implement proper NIO proxy support and remove synchronous support from
send/disconnect.
This commit is contained in:
parent
d05bdadbbf
commit
d725ce0d79
8 changed files with 178 additions and 96 deletions
2
pom.xml
2
pom.xml
|
@ -49,7 +49,7 @@
|
|||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.42.Final</version>
|
||||
<version>4.1.45.Final</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
106
src/main/java/com/github/steveice10/packetlib/ProxyInfo.java
Normal file
106
src/main/java/com/github/steveice10/packetlib/ProxyInfo.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
package com.github.steveice10.packetlib;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
|
||||
/**
|
||||
* Information describing a network proxy.
|
||||
*/
|
||||
public class ProxyInfo {
|
||||
private Type type;
|
||||
private SocketAddress address;
|
||||
private boolean authenticated;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* Creates a new unauthenticated ProxyInfo instance.
|
||||
*
|
||||
* @param type Type of proxy.
|
||||
* @param address Network address of the proxy.
|
||||
*/
|
||||
public ProxyInfo(Type type, SocketAddress address) {
|
||||
this.type = type;
|
||||
this.address = address;
|
||||
this.authenticated = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new authenticated ProxyInfo instance.
|
||||
*
|
||||
* @param type Type of proxy.
|
||||
* @param address Network address of the proxy.
|
||||
* @param username Username to authenticate with.
|
||||
* @param password Password to authenticate with.
|
||||
*/
|
||||
public ProxyInfo(Type type, SocketAddress address, String username, String password) {
|
||||
this(type, address);
|
||||
this.authenticated = true;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proxy's type.
|
||||
*
|
||||
* @return The proxy's type.
|
||||
*/
|
||||
public Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proxy's network address.
|
||||
*
|
||||
* @return The proxy's network address.
|
||||
*/
|
||||
public SocketAddress getAddress() {
|
||||
return this.address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the proxy is authenticated with.
|
||||
*
|
||||
* @return Whether to authenticate with the proxy.
|
||||
*/
|
||||
public boolean isAuthenticated() {
|
||||
return this.authenticated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proxy's authentication username.
|
||||
*
|
||||
* @return The username to authenticate with.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proxy's authentication password.
|
||||
*
|
||||
* @return The password to authenticate with.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported proxy types.
|
||||
*/
|
||||
public enum Type {
|
||||
/**
|
||||
* HTTP proxy.
|
||||
*/
|
||||
HTTP,
|
||||
|
||||
/**
|
||||
* SOCKS4 proxy.
|
||||
*/
|
||||
SOCKS4,
|
||||
|
||||
/**
|
||||
* SOCKS5 proxy.
|
||||
*/
|
||||
SOCKS5;
|
||||
}
|
||||
}
|
|
@ -89,6 +89,19 @@ public interface Session {
|
|||
*/
|
||||
public <T> T getFlag(String key);
|
||||
|
||||
/**
|
||||
* Gets the value of the given flag as an instance of the given type. If this
|
||||
* session belongs to a server, the server's flags will be checked for the flag
|
||||
* as well. If no flag is found, the specified default value will be returned.
|
||||
*
|
||||
* @param <T> Type of the flag.
|
||||
* @param key Key of the flag.
|
||||
* @param def Default value of the flag.
|
||||
* @return Value of the flag.
|
||||
* @throws IllegalStateException If the flag's value isn't of the required type.
|
||||
*/
|
||||
public <T> T getFlag(String key, T def);
|
||||
|
||||
/**
|
||||
* Sets the value of a flag. This does not change a server's flags if this session
|
||||
* belongs to a server.
|
||||
|
@ -203,14 +216,6 @@ public interface Session {
|
|||
*/
|
||||
public void disconnect(String reason);
|
||||
|
||||
/**
|
||||
* Disconnects the session.
|
||||
*
|
||||
* @param reason Reason for disconnecting.
|
||||
* @param wait Whether to wait for the session to be disconnected.
|
||||
*/
|
||||
public void disconnect(String reason, boolean wait);
|
||||
|
||||
/**
|
||||
* Disconnects the session.
|
||||
*
|
||||
|
@ -218,13 +223,4 @@ public interface Session {
|
|||
* @param cause Throwable responsible for disconnecting.
|
||||
*/
|
||||
public void disconnect(String reason, Throwable cause);
|
||||
|
||||
/**
|
||||
* Disconnects the session.
|
||||
*
|
||||
* @param reason Reason for disconnecting.
|
||||
* @param cause Throwable responsible for disconnecting.
|
||||
* @param wait Whether to wait for the session to be disconnected.
|
||||
*/
|
||||
public void disconnect(String reason, Throwable cause, boolean wait);
|
||||
}
|
||||
|
|
|
@ -26,9 +26,9 @@ public interface Packet {
|
|||
public void write(NetOutput out) throws IOException;
|
||||
|
||||
/**
|
||||
* Gets whether the packet has handling and writing priority.
|
||||
* If the result is true, the thread will wait for the packet to finish writing
|
||||
* when writing and the packet will be handled immediately after reading it.
|
||||
* Gets whether the packet has handling priority.
|
||||
* If the result is true, the packet will be handled immediately after being
|
||||
* decoded.
|
||||
*
|
||||
* @return Whether the packet has priority.
|
||||
*/
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
package com.github.steveice10.packetlib.tcp;
|
||||
|
||||
import io.netty.channel.ChannelFactory;
|
||||
import io.netty.channel.socket.oio.OioSocketChannel;
|
||||
|
||||
import java.net.Proxy;
|
||||
import java.net.Socket;
|
||||
|
||||
public class ProxyOioChannelFactory implements ChannelFactory<OioSocketChannel> {
|
||||
private Proxy proxy;
|
||||
|
||||
public ProxyOioChannelFactory(Proxy proxy) {
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OioSocketChannel newChannel() {
|
||||
return new OioSocketChannel(new Socket(this.proxy));
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.github.steveice10.packetlib.tcp;
|
||||
|
||||
import com.github.steveice10.packetlib.Client;
|
||||
import com.github.steveice10.packetlib.ProxyInfo;
|
||||
import com.github.steveice10.packetlib.packet.PacketProtocol;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
|
@ -10,21 +11,22 @@ import io.netty.channel.ChannelOption;
|
|||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.oio.OioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.proxy.HttpProxyHandler;
|
||||
import io.netty.handler.proxy.Socks4ProxyHandler;
|
||||
import io.netty.handler.proxy.Socks5ProxyHandler;
|
||||
import io.netty.util.concurrent.Future;
|
||||
|
||||
import javax.naming.directory.InitialDirContext;
|
||||
import java.net.Proxy;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class TcpClientSession extends TcpSession {
|
||||
private Client client;
|
||||
private Proxy proxy;
|
||||
private ProxyInfo proxy;
|
||||
|
||||
private EventLoopGroup group;
|
||||
|
||||
public TcpClientSession(String host, int port, PacketProtocol protocol, Client client, Proxy proxy) {
|
||||
public TcpClientSession(String host, int port, PacketProtocol protocol, Client client, ProxyInfo proxy) {
|
||||
super(host, port, protocol);
|
||||
this.client = client;
|
||||
this.proxy = proxy;
|
||||
|
@ -39,15 +41,10 @@ public class TcpClientSession extends TcpSession {
|
|||
}
|
||||
|
||||
try {
|
||||
final Bootstrap bootstrap = new Bootstrap();
|
||||
if(this.proxy != null) {
|
||||
this.group = new OioEventLoopGroup();
|
||||
bootstrap.channelFactory(new ProxyOioChannelFactory(this.proxy));
|
||||
} else {
|
||||
this.group = new NioEventLoopGroup();
|
||||
bootstrap.channel(NioSocketChannel.class);
|
||||
}
|
||||
this.group = new NioEventLoopGroup();
|
||||
|
||||
final Bootstrap bootstrap = new Bootstrap();
|
||||
bootstrap.channel(NioSocketChannel.class);
|
||||
bootstrap.handler(new ChannelInitializer<Channel>() {
|
||||
@Override
|
||||
public void initChannel(Channel channel) throws Exception {
|
||||
|
@ -61,6 +58,37 @@ 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());
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.addLast("encryption", new TcpPacketEncryptor(TcpClientSession.this));
|
||||
pipeline.addLast("sizer", new TcpPacketSizer(TcpClientSession.this));
|
||||
pipeline.addLast("codec", new TcpPacketCodec(TcpClientSession.this));
|
||||
|
@ -117,17 +145,10 @@ public class TcpClientSession extends TcpSession {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String reason, Throwable cause, boolean wait) {
|
||||
super.disconnect(reason, cause, wait);
|
||||
public void disconnect(String reason, Throwable cause) {
|
||||
super.disconnect(reason, cause);
|
||||
if(this.group != null) {
|
||||
Future<?> future = this.group.shutdownGracefully();
|
||||
if(wait) {
|
||||
try {
|
||||
future.await();
|
||||
} catch(InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
this.group.shutdownGracefully();
|
||||
this.group = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,9 +104,14 @@ public abstract class TcpSession extends SimpleChannelInboundHandler<Packet> imp
|
|||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T getFlag(String key) {
|
||||
return this.getFlag(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getFlag(String key, T def) {
|
||||
Object value = this.getFlags().get(key);
|
||||
if(value == null) {
|
||||
return null;
|
||||
return def;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -214,8 +219,7 @@ public abstract class TcpSession extends SimpleChannelInboundHandler<Packet> imp
|
|||
|
||||
if(!sendingEvent.isCancelled()) {
|
||||
final Packet toSend = sendingEvent.getPacket();
|
||||
|
||||
ChannelFuture future = this.channel.writeAndFlush(toSend).addListener(new ChannelFutureListener() {
|
||||
this.channel.writeAndFlush(toSend).addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if(future.isSuccess()) {
|
||||
|
@ -225,33 +229,16 @@ public abstract class TcpSession extends SimpleChannelInboundHandler<Packet> imp
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(toSend.isPriority()) {
|
||||
try {
|
||||
future.await();
|
||||
} catch(InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String reason) {
|
||||
this.disconnect(reason, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String reason, boolean wait) {
|
||||
this.disconnect(reason, null, wait);
|
||||
this.disconnect(reason, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(final String reason, final Throwable cause) {
|
||||
this.disconnect(reason, cause, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(final String reason, final Throwable cause, boolean wait) {
|
||||
if(this.disconnected) {
|
||||
return;
|
||||
}
|
||||
|
@ -265,19 +252,12 @@ public abstract class TcpSession extends SimpleChannelInboundHandler<Packet> imp
|
|||
|
||||
if(this.channel != null && this.channel.isOpen()) {
|
||||
this.callEvent(new DisconnectingEvent(this, reason, cause));
|
||||
ChannelFuture future = this.channel.flush().close().addListener(new ChannelFutureListener() {
|
||||
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));
|
||||
}
|
||||
});
|
||||
|
||||
if(wait) {
|
||||
try {
|
||||
future.await();
|
||||
} catch(InterruptedException e) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.callEvent(new DisconnectedEvent(this, reason != null ? reason : "Connection closed.", cause));
|
||||
}
|
||||
|
|
|
@ -2,22 +2,21 @@ 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;
|
||||
|
||||
import java.net.Proxy;
|
||||
|
||||
/**
|
||||
* A session factory used to create TCP sessions.
|
||||
*/
|
||||
public class TcpSessionFactory implements SessionFactory {
|
||||
private Proxy clientProxy;
|
||||
private ProxyInfo clientProxy;
|
||||
|
||||
public TcpSessionFactory() {
|
||||
}
|
||||
|
||||
public TcpSessionFactory(Proxy clientProxy) {
|
||||
public TcpSessionFactory(ProxyInfo clientProxy) {
|
||||
this.clientProxy = clientProxy;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue