mirror of
https://github.com/GeyserMC/MCProtocolLib.git
synced 2024-11-14 19:34:58 -05:00
Collapse Client and Server into *ClientSession and ConnectionListener.
This commit is contained in:
parent
87206da886
commit
19a9b2be35
14 changed files with 356 additions and 552 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue